{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "XuXWJLEm2UWS"
   },
   "source": [
    "# **CS224W - Colab 5**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8gzsP50bF6Gb"
   },
   "source": [
    "In this Colab we will experiment on scaling up GNNs using PyTorch Geometric, DeepSNAP and NetworkX. As we have **canceled** the Colab 5 assignment, this notebook will be a tutorial and you do not need to submit it on Gradescope.\n",
    "\n",
    "At first, we will use PyTorch Geometric `NeighborSampler` to scale up the training and testing on OGB `arxiv` dataset.\n",
    "\n",
    "Then, using the DeepSNAP and NetworkX, we will implement a simplified version of `NeighborSampler` and run experiments with different smapling ratios on the Cora graph.\n",
    "\n",
    "At last, we will partition the Cora graph into clusters by using different partition algorithms and then train the models in the way of vanilla Cluster-GCN.\n",
    "\n",
    "**Note**: Make sure to **sequentially run all the cells in each section**, so that the intermediate variables / packages will carry over to the next cell"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "id": "PRfgbfTjCRD_"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1.6.3'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch_geometric\n",
    "torch_geometric.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SxkYLgxAOxz7"
   },
   "source": [
    "# 1 PyTorch Geometric Neighbor Sampling\n",
    "\n",
    "Neighbor Sampling, originally proposed in **GraphSAGE** ([Hamilton et al. (2017)](https://arxiv.org/abs/1706.02216)), is a representative method to scale up GNNs. As what we have learned in lecture, only a K-hop neighborhood nodes will be loaded into GPU for each time training. To further reduce the cost, we can sample a subset of neighborhood nodes for GNNs to aggregate."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Kho6SHUVO1ny"
   },
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "X1WJLGKsOx_k"
   },
   "outputs": [],
   "source": [
    "import copy\n",
    "import torch\n",
    "import torch.nn.functional as F\n",
    "import torch_geometric.transforms as T\n",
    "\n",
    "from torch_geometric.nn import SAGEConv\n",
    "from torch_geometric.data import NeighborSampler\n",
    "from ogb.nodeproppred import PygNodePropPredDataset, Evaluator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UKqZWqRbO7km"
   },
   "source": [
    "## Neighbor Sampler\n",
    "\n",
    "PyTorch Geometric has implemented the Neighbor Sampling method as the [NeighborSampler](https://pytorch-geometric.readthedocs.io/en/latest/modules/data.html#torch_geometric.data.NeighborSampler) in `torch_geometric.data`. Following is an example that uses the Neighbor Sampling method on training the OGB `arxiv` dataset.\n",
    "\n",
    "If you are interested in memory-efficient aggregations, please refer to PyG's [Memory-Efficient Aggregations](https://pytorch-geometric.readthedocs.io/en/latest/notes/sparse_tensor.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "nWlyStlRO6_u"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:The OGB package is out of date. Your version is 1.3.0, while the latest version is 1.3.1.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Device: cuda\n"
     ]
    }
   ],
   "source": [
    "dataset_name = 'ogbn-arxiv'\n",
    "dataset = PygNodePropPredDataset(name=dataset_name,\n",
    "                                 transform=T.ToSparseTensor())\n",
    "data = dataset[0]\n",
    "data.adj_t = data.adj_t.to_symmetric()\n",
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
    "\n",
    "print('Device: {}'.format(device))\n",
    "\n",
    "data = data.to(device)\n",
    "split_idx = dataset.get_idx_split()\n",
    "train_idx = split_idx['train'].to(device)\n",
    "\n",
    "# Construct the training dataloader for training data\n",
    "# Sample 10 neighbors for each node in the first layer and 5 for the second layer\n",
    "train_loader = NeighborSampler(data.adj_t, node_idx=train_idx,\n",
    "                               sizes=[10, 5], batch_size=4096,\n",
    "                               shuffle=True, num_workers=2)\n",
    "\n",
    "# Specify size as -1 to include all neighbors\n",
    "all_loader = NeighborSampler(data.adj_t, node_idx=None, sizes=[-1],\n",
    "                                  batch_size=4096, shuffle=False,\n",
    "                                  num_workers=2)\n",
    "evaluator = Evaluator(name='ogbn-arxiv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "VjdkIcFpRYyl"
   },
   "source": [
    "## GNN Model\n",
    "\n",
    "After creating the `NeighborSampler`, we also need to modify the model to let it support the mini-batch training.\n",
    "\n",
    "The `forward` function will take the node feature `x` and a list of three-element tuples `adjs`. Each element in `adjs` contains following elements:\n",
    "* `edge_index`: The edge index tensor between source and destination nodes, which forms a bipartite grpah.\n",
    "* `e_id`: The indices of the edges in the original graph.\n",
    "* `size`: The shape of the bipartite graph, in (*number of source nodes*, *number of destination nodes*) format."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "gRBJS_5qRWbu"
   },
   "outputs": [],
   "source": [
    "class SAGE(torch.nn.Module):\n",
    "    def __init__(self, input_dim, hidden_dim, output_dim, num_layers,\n",
    "                 dropout):\n",
    "        super(SAGE, self).__init__()\n",
    "\n",
    "        self.convs = torch.nn.ModuleList()\n",
    "        self.bns = torch.nn.ModuleList()\n",
    "\n",
    "        self.convs.append(SAGEConv(input_dim, hidden_dim))\n",
    "        self.bns.append(torch.nn.BatchNorm1d(hidden_dim))\n",
    "\n",
    "        for i in range(num_layers - 2):\n",
    "            self.convs.append(\n",
    "                SAGEConv(hidden_dim, hidden_dim))\n",
    "            self.bns.append(torch.nn.BatchNorm1d(hidden_dim))\n",
    "        self.convs.append(SAGEConv(hidden_dim, output_dim))\n",
    "\n",
    "        self.softmax = torch.nn.LogSoftmax(dim=1)\n",
    "\n",
    "        self.dropout = dropout\n",
    "\n",
    "        self.num_layers = num_layers\n",
    "\n",
    "    def reset_parameters(self):\n",
    "        for conv in self.convs:\n",
    "            conv.reset_parameters()\n",
    "        for bn in self.bns:\n",
    "            bn.reset_parameters()\n",
    "\n",
    "    def forward(self, x, adjs, mode=\"batch\"):\n",
    "        if mode == \"batch\":\n",
    "            for i, (edge_index, _, size) in enumerate(adjs):\n",
    "                # Extract target node features\n",
    "                x_target = x[:size[1]]\n",
    "\n",
    "                # Update x for next layer reuse\n",
    "                x = self.convs[i]((x, x_target), edge_index)\n",
    "                if i != self.num_layers - 1:\n",
    "                    x = self.bns[i](x)\n",
    "                    x = F.relu(x)\n",
    "                    x = F.dropout(x, p=self.dropout, training=self.training)\n",
    "        else:\n",
    "            for i, conv in enumerate(self.convs):\n",
    "                x = conv(x, adjs)\n",
    "                if i != self.num_layers - 1:\n",
    "                    x = self.bns[i](x)\n",
    "                    x = F.relu(x)\n",
    "                    x = F.dropout(x, p=self.dropout, training=self.training)\n",
    "        return self.softmax(x)\n",
    "    \n",
    "    def inference(self, x_all, all_loader):\n",
    "        # This function will be called in test\n",
    "        for i in range(self.num_layers):\n",
    "            xs = []\n",
    "            for batch_size, n_id, adj in all_loader:\n",
    "                edge_index, _, size = adj.to(device)\n",
    "                x = x_all[n_id].to(device)\n",
    "                x_target = x[:size[1]]\n",
    "                x = self.convs[i]((x, x_target), edge_index)\n",
    "                if i != self.num_layers - 1:\n",
    "                    x = self.bns[i](x)\n",
    "                    x = F.relu(x)\n",
    "                    x = F.dropout(x, p=self.dropout, training=self.training)\n",
    "                \n",
    "                # Append the node embeddings to xs\n",
    "                xs.append(x.cpu())\n",
    "            \n",
    "            # Concat all embeddings into one tensor\n",
    "            x_all = torch.cat(xs, dim=0)\n",
    "\n",
    "        return x_all"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7cfm7K3wRqqY"
   },
   "source": [
    "## Training and Testing\n",
    "\n",
    "Now lets implement the training and testing functions.\n",
    "\n",
    "In both training and testing, we need to sample batch from the dataloader.\n",
    "\n",
    "Each batch in the `NeighborSampler` dataloader holds three elements:\n",
    "* `batch_size`: The batch size specified in the dataloader.\n",
    "* `n_id`: All nodes (in index format) used in the adjacency matrices.\n",
    "* `adjs`: The three-element tuples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "-JN0-_QCRn8N"
   },
   "outputs": [],
   "source": [
    "def train(model, data, train_loader, train_idx, optimizer, loss_fn, mode=\"batch\"):\n",
    "    model.train()\n",
    "\n",
    "    total_loss = 0\n",
    "    if mode == \"batch\":\n",
    "        for batch_size, n_id, adjs in train_loader:\n",
    "            # Move all adj sparse tensors to GPU\n",
    "            adjs = [adj.to(device) for adj in adjs]\n",
    "            optimizer.zero_grad()\n",
    "\n",
    "            # Index on the node features\n",
    "            out = model(data.x[n_id], adjs)\n",
    "            train_label = data.y[n_id[:batch_size]].squeeze(-1)\n",
    "            loss = loss_fn(out, train_label)\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "            total_loss += loss.item()\n",
    "    else:\n",
    "        optimizer.zero_grad()\n",
    "        out = model(data.x, data.adj_t, mode=mode)[train_idx]\n",
    "        train_label = data.y.squeeze(1)[train_idx]\n",
    "        loss = loss_fn(out, train_label)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        total_loss = loss.item()\n",
    "\n",
    "    return total_loss\n",
    "\n",
    "@torch.no_grad()\n",
    "def test(model, data, all_loader, split_idx, evaluator, mode=\"batch\"):\n",
    "    model.eval()\n",
    "\n",
    "    if mode == \"batch\":\n",
    "        out = model.inference(data.x, all_loader)\n",
    "    else:\n",
    "        out = model(data.x, data.adj_t, mode=\"all\")\n",
    "\n",
    "    y_true = data.y.cpu()\n",
    "    y_pred = out.argmax(dim=-1, keepdim=True)\n",
    "\n",
    "    train_acc = evaluator.eval({\n",
    "        'y_true': y_true[split_idx['train']],\n",
    "        'y_pred': y_pred[split_idx['train']],\n",
    "    })['acc']\n",
    "    valid_acc = evaluator.eval({\n",
    "        'y_true': y_true[split_idx['valid']],\n",
    "        'y_pred': y_pred[split_idx['valid']],\n",
    "    })['acc']\n",
    "    test_acc = evaluator.eval({\n",
    "        'y_true': y_true[split_idx['test']],\n",
    "        'y_pred': y_pred[split_idx['test']],\n",
    "    })['acc']\n",
    "\n",
    "    return train_acc, valid_acc, test_acc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AiehZ8OiR2q9"
   },
   "source": [
    "## Mini-batch Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "id": "zFaI2eCARy0v"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 01, Loss: 40.1146, Train: 63.50%, Valid: 63.57% Test: 62.20%\n",
      "Epoch: 02, Loss: 28.4567, Train: 67.34%, Valid: 66.91% Test: 65.92%\n",
      "Epoch: 03, Loss: 26.4881, Train: 68.86%, Valid: 68.59% Test: 68.55%\n",
      "Epoch: 04, Loss: 25.4927, Train: 69.90%, Valid: 68.51% Test: 66.66%\n",
      "Epoch: 05, Loss: 25.0484, Train: 70.72%, Valid: 69.68% Test: 68.68%\n",
      "Epoch: 06, Loss: 24.5342, Train: 71.37%, Valid: 69.68% Test: 68.66%\n",
      "Epoch: 07, Loss: 24.1294, Train: 71.53%, Valid: 68.79% Test: 67.18%\n",
      "Epoch: 08, Loss: 23.8874, Train: 72.03%, Valid: 70.22% Test: 69.96%\n",
      "Epoch: 09, Loss: 23.6965, Train: 71.97%, Valid: 69.57% Test: 68.72%\n",
      "Epoch: 10, Loss: 23.5053, Train: 72.42%, Valid: 69.82% Test: 68.63%\n",
      "Epoch: 11, Loss: 23.2913, Train: 72.21%, Valid: 69.96% Test: 68.71%\n",
      "Epoch: 12, Loss: 23.0910, Train: 72.54%, Valid: 69.18% Test: 67.47%\n",
      "Epoch: 13, Loss: 23.0367, Train: 73.03%, Valid: 69.36% Test: 67.64%\n",
      "Epoch: 14, Loss: 22.8411, Train: 73.16%, Valid: 70.26% Test: 69.42%\n",
      "Epoch: 15, Loss: 22.7898, Train: 73.43%, Valid: 70.21% Test: 69.32%\n",
      "Epoch: 16, Loss: 22.5725, Train: 73.38%, Valid: 70.53% Test: 69.97%\n",
      "Epoch: 17, Loss: 22.4906, Train: 73.64%, Valid: 70.23% Test: 69.34%\n",
      "Epoch: 18, Loss: 22.3508, Train: 73.58%, Valid: 70.43% Test: 69.50%\n",
      "Epoch: 19, Loss: 22.2035, Train: 73.11%, Valid: 69.95% Test: 69.00%\n",
      "Epoch: 20, Loss: 22.2971, Train: 73.84%, Valid: 69.39% Test: 67.31%\n",
      "Epoch: 21, Loss: 22.2129, Train: 74.16%, Valid: 71.00% Test: 70.22%\n",
      "Epoch: 22, Loss: 22.0411, Train: 74.51%, Valid: 70.69% Test: 70.10%\n",
      "Epoch: 23, Loss: 22.0265, Train: 74.04%, Valid: 70.58% Test: 70.57%\n",
      "Epoch: 24, Loss: 22.0342, Train: 74.29%, Valid: 69.80% Test: 67.92%\n",
      "Epoch: 25, Loss: 21.8363, Train: 74.76%, Valid: 70.93% Test: 70.13%\n",
      "Epoch: 26, Loss: 21.7350, Train: 74.79%, Valid: 70.68% Test: 69.60%\n",
      "Epoch: 27, Loss: 21.7216, Train: 74.50%, Valid: 70.60% Test: 70.14%\n",
      "Epoch: 28, Loss: 21.6747, Train: 74.91%, Valid: 70.58% Test: 69.42%\n",
      "Epoch: 29, Loss: 21.6489, Train: 74.87%, Valid: 70.87% Test: 69.82%\n",
      "Epoch: 30, Loss: 21.6166, Train: 75.10%, Valid: 70.89% Test: 69.58%\n",
      "Epoch: 31, Loss: 21.5630, Train: 75.14%, Valid: 70.41% Test: 69.31%\n",
      "Epoch: 32, Loss: 21.5094, Train: 75.12%, Valid: 71.00% Test: 70.51%\n",
      "Epoch: 33, Loss: 21.5251, Train: 75.10%, Valid: 70.99% Test: 69.96%\n",
      "Epoch: 34, Loss: 21.3742, Train: 75.13%, Valid: 70.25% Test: 68.67%\n",
      "Epoch: 35, Loss: 21.5106, Train: 75.28%, Valid: 70.52% Test: 68.84%\n",
      "Epoch: 36, Loss: 21.4713, Train: 75.45%, Valid: 70.99% Test: 69.69%\n",
      "Epoch: 37, Loss: 21.1744, Train: 75.24%, Valid: 70.43% Test: 68.81%\n",
      "Epoch: 38, Loss: 21.2626, Train: 75.42%, Valid: 70.43% Test: 68.64%\n",
      "Epoch: 39, Loss: 21.2062, Train: 75.45%, Valid: 70.70% Test: 69.13%\n",
      "Epoch: 40, Loss: 21.2035, Train: 75.83%, Valid: 70.97% Test: 69.88%\n",
      "Epoch: 41, Loss: 20.9957, Train: 75.70%, Valid: 71.07% Test: 70.18%\n",
      "Epoch: 42, Loss: 21.0509, Train: 75.70%, Valid: 70.72% Test: 69.09%\n",
      "Epoch: 43, Loss: 20.9997, Train: 75.43%, Valid: 70.85% Test: 70.34%\n",
      "Epoch: 44, Loss: 21.1264, Train: 75.91%, Valid: 71.26% Test: 69.95%\n",
      "Epoch: 45, Loss: 21.1188, Train: 75.81%, Valid: 70.38% Test: 68.45%\n",
      "Epoch: 46, Loss: 21.1081, Train: 75.71%, Valid: 70.81% Test: 69.68%\n",
      "Epoch: 47, Loss: 20.9439, Train: 75.74%, Valid: 70.69% Test: 70.05%\n",
      "Epoch: 48, Loss: 20.9572, Train: 76.00%, Valid: 70.81% Test: 69.52%\n",
      "Epoch: 49, Loss: 20.9323, Train: 76.20%, Valid: 71.38% Test: 70.80%\n",
      "Epoch: 50, Loss: 21.0087, Train: 75.95%, Valid: 70.81% Test: 69.53%\n",
      "Epoch: 51, Loss: 20.8615, Train: 76.22%, Valid: 71.06% Test: 70.39%\n",
      "Epoch: 52, Loss: 20.9196, Train: 76.24%, Valid: 71.17% Test: 70.26%\n",
      "Epoch: 53, Loss: 20.7706, Train: 76.07%, Valid: 71.27% Test: 70.37%\n",
      "Epoch: 54, Loss: 20.8715, Train: 75.90%, Valid: 70.82% Test: 69.49%\n",
      "Epoch: 55, Loss: 20.7520, Train: 76.28%, Valid: 70.75% Test: 69.24%\n",
      "Epoch: 56, Loss: 20.8949, Train: 76.46%, Valid: 71.15% Test: 70.09%\n",
      "Epoch: 57, Loss: 20.7263, Train: 76.28%, Valid: 70.95% Test: 69.68%\n",
      "Epoch: 58, Loss: 20.6850, Train: 76.18%, Valid: 70.56% Test: 68.99%\n",
      "Epoch: 59, Loss: 20.7723, Train: 76.35%, Valid: 70.58% Test: 69.34%\n",
      "Epoch: 60, Loss: 20.7555, Train: 76.19%, Valid: 71.13% Test: 70.79%\n",
      "Epoch: 61, Loss: 20.6582, Train: 76.43%, Valid: 70.63% Test: 69.11%\n",
      "Epoch: 62, Loss: 20.6769, Train: 76.47%, Valid: 71.34% Test: 70.29%\n",
      "Epoch: 63, Loss: 20.6466, Train: 76.51%, Valid: 70.93% Test: 69.55%\n",
      "Epoch: 64, Loss: 20.5834, Train: 76.51%, Valid: 70.40% Test: 68.74%\n",
      "Epoch: 65, Loss: 20.6625, Train: 76.77%, Valid: 71.21% Test: 70.20%\n",
      "Epoch: 66, Loss: 20.5731, Train: 76.72%, Valid: 70.83% Test: 69.76%\n",
      "Epoch: 67, Loss: 20.5373, Train: 76.60%, Valid: 71.14% Test: 70.14%\n",
      "Epoch: 68, Loss: 20.5094, Train: 76.72%, Valid: 71.07% Test: 69.90%\n",
      "Epoch: 69, Loss: 20.5277, Train: 76.40%, Valid: 70.42% Test: 68.95%\n",
      "Epoch: 70, Loss: 20.6146, Train: 76.77%, Valid: 71.13% Test: 70.49%\n",
      "Epoch: 71, Loss: 20.6751, Train: 76.53%, Valid: 70.70% Test: 69.40%\n",
      "Epoch: 72, Loss: 20.5618, Train: 76.52%, Valid: 69.82% Test: 67.56%\n",
      "Epoch: 73, Loss: 20.5725, Train: 76.63%, Valid: 70.95% Test: 69.91%\n",
      "Epoch: 74, Loss: 20.4649, Train: 76.89%, Valid: 71.07% Test: 69.98%\n",
      "Epoch: 75, Loss: 20.4679, Train: 76.91%, Valid: 70.96% Test: 69.97%\n",
      "Epoch: 76, Loss: 20.4778, Train: 76.71%, Valid: 71.10% Test: 69.91%\n",
      "Epoch: 77, Loss: 20.4377, Train: 77.00%, Valid: 71.10% Test: 69.50%\n",
      "Epoch: 78, Loss: 20.4682, Train: 76.70%, Valid: 70.87% Test: 69.44%\n",
      "Epoch: 79, Loss: 20.5316, Train: 76.81%, Valid: 71.02% Test: 69.49%\n",
      "Epoch: 80, Loss: 20.4651, Train: 76.88%, Valid: 70.16% Test: 68.31%\n",
      "Epoch: 81, Loss: 20.3808, Train: 76.97%, Valid: 70.95% Test: 69.90%\n",
      "Epoch: 82, Loss: 20.4075, Train: 76.83%, Valid: 70.15% Test: 68.42%\n",
      "Epoch: 83, Loss: 20.2842, Train: 77.11%, Valid: 71.20% Test: 70.35%\n",
      "Epoch: 84, Loss: 20.3433, Train: 76.76%, Valid: 71.02% Test: 70.32%\n",
      "Epoch: 85, Loss: 20.3711, Train: 77.01%, Valid: 70.79% Test: 69.48%\n",
      "Epoch: 86, Loss: 20.3444, Train: 77.01%, Valid: 71.20% Test: 70.16%\n",
      "Epoch: 87, Loss: 20.2844, Train: 76.92%, Valid: 71.05% Test: 70.13%\n",
      "Epoch: 88, Loss: 20.3590, Train: 77.30%, Valid: 71.25% Test: 70.02%\n",
      "Epoch: 89, Loss: 20.3068, Train: 76.92%, Valid: 71.21% Test: 70.12%\n",
      "Epoch: 90, Loss: 20.3385, Train: 77.18%, Valid: 70.74% Test: 69.40%\n",
      "Epoch: 91, Loss: 20.3073, Train: 77.23%, Valid: 70.58% Test: 69.08%\n",
      "Epoch: 92, Loss: 20.2952, Train: 77.24%, Valid: 70.86% Test: 69.38%\n",
      "Epoch: 93, Loss: 20.1759, Train: 77.35%, Valid: 71.10% Test: 69.60%\n",
      "Epoch: 94, Loss: 20.1965, Train: 77.10%, Valid: 70.52% Test: 68.43%\n",
      "Epoch: 95, Loss: 20.3626, Train: 77.36%, Valid: 71.00% Test: 69.86%\n",
      "Epoch: 96, Loss: 20.1572, Train: 77.19%, Valid: 70.92% Test: 69.56%\n",
      "Epoch: 97, Loss: 20.2364, Train: 77.39%, Valid: 71.17% Test: 70.08%\n",
      "Epoch: 98, Loss: 20.2570, Train: 77.11%, Valid: 70.87% Test: 68.94%\n",
      "Epoch: 99, Loss: 20.1866, Train: 77.50%, Valid: 70.91% Test: 69.58%\n",
      "Epoch: 100, Loss: 20.1771, Train: 77.41%, Valid: 71.15% Test: 69.68%\n",
      "Best model: Train: 76.20%, Valid: 71.38% Test: 70.80%\n"
     ]
    }
   ],
   "source": [
    "args = {\n",
    "    'device': device,\n",
    "    'num_layers': 2,\n",
    "    'hidden_dim': 128,\n",
    "    'dropout': 0.5,\n",
    "    'lr': 0.01,\n",
    "    'epochs': 100,\n",
    "}\n",
    "\n",
    "batch_model = SAGE(data.num_features, args['hidden_dim'],\n",
    "            dataset.num_classes, args['num_layers'],\n",
    "            args['dropout']).to(device)\n",
    "batch_model.reset_parameters()\n",
    "\n",
    "optimizer = torch.optim.Adam(batch_model.parameters(), lr=args['lr'])\n",
    "loss_fn = F.nll_loss\n",
    "\n",
    "best_batch_model = None\n",
    "best_valid_acc = 0\n",
    "\n",
    "batch_results = []\n",
    "\n",
    "for epoch in range(1, 1 + args[\"epochs\"]):\n",
    "    loss = train(batch_model, data, train_loader, train_idx, optimizer, loss_fn, mode=\"batch\")\n",
    "    result = test(batch_model, data, all_loader, split_idx, evaluator, mode=\"batch\")\n",
    "    batch_results.append(result)\n",
    "    train_acc, valid_acc, test_acc = result\n",
    "    if valid_acc > best_valid_acc:\n",
    "        best_valid_acc = valid_acc\n",
    "        best_batch_model = copy.deepcopy(batch_model)\n",
    "    print(f'Epoch: {epoch:02d}, '\n",
    "          f'Loss: {loss:.4f}, '\n",
    "          f'Train: {100 * train_acc:.2f}%, '\n",
    "          f'Valid: {100 * valid_acc:.2f}% '\n",
    "          f'Test: {100 * test_acc:.2f}%')\n",
    "best_result = test(best_batch_model, data, all_loader, split_idx, evaluator, mode=\"batch\")\n",
    "train_acc, valid_acc, test_acc = best_result\n",
    "print(f'Best model: '\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * valid_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-OyqW-1pSMLW"
   },
   "source": [
    "## Full-batch Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "id": "mU5eAviTSFMO"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 01, Loss: 4.0016, Train: 22.20%, Valid: 16.32% Test: 15.22%\n",
      "Epoch: 02, Loss: 2.5952, Train: 28.98%, Valid: 32.37% Test: 34.69%\n",
      "Epoch: 03, Loss: 2.1824, Train: 34.65%, Valid: 42.74% Test: 45.91%\n",
      "Epoch: 04, Loss: 1.9973, Train: 38.85%, Valid: 47.18% Test: 50.01%\n",
      "Epoch: 05, Loss: 1.8617, Train: 43.93%, Valid: 50.72% Test: 53.17%\n",
      "Epoch: 06, Loss: 1.7696, Train: 47.52%, Valid: 53.15% Test: 55.11%\n",
      "Epoch: 07, Loss: 1.6885, Train: 49.76%, Valid: 54.62% Test: 56.20%\n",
      "Epoch: 08, Loss: 1.6284, Train: 51.53%, Valid: 56.00% Test: 57.23%\n",
      "Epoch: 09, Loss: 1.5837, Train: 53.19%, Valid: 57.66% Test: 58.70%\n",
      "Epoch: 10, Loss: 1.5456, Train: 54.80%, Valid: 58.87% Test: 59.50%\n",
      "Epoch: 11, Loss: 1.5094, Train: 56.07%, Valid: 59.70% Test: 59.84%\n",
      "Epoch: 12, Loss: 1.4708, Train: 56.96%, Valid: 60.08% Test: 59.89%\n",
      "Epoch: 13, Loss: 1.4413, Train: 57.76%, Valid: 60.41% Test: 60.24%\n",
      "Epoch: 14, Loss: 1.4173, Train: 58.40%, Valid: 60.70% Test: 60.66%\n",
      "Epoch: 15, Loss: 1.3947, Train: 58.92%, Valid: 61.21% Test: 61.24%\n",
      "Epoch: 16, Loss: 1.3739, Train: 59.46%, Valid: 61.77% Test: 61.94%\n",
      "Epoch: 17, Loss: 1.3583, Train: 59.97%, Valid: 62.29% Test: 62.72%\n",
      "Epoch: 18, Loss: 1.3432, Train: 60.56%, Valid: 62.71% Test: 63.33%\n",
      "Epoch: 19, Loss: 1.3280, Train: 61.16%, Valid: 63.15% Test: 63.80%\n",
      "Epoch: 20, Loss: 1.3129, Train: 61.87%, Valid: 63.84% Test: 64.33%\n",
      "Epoch: 21, Loss: 1.2934, Train: 62.59%, Valid: 64.46% Test: 64.85%\n",
      "Epoch: 22, Loss: 1.2869, Train: 63.24%, Valid: 65.01% Test: 65.19%\n",
      "Epoch: 23, Loss: 1.2759, Train: 63.67%, Valid: 65.38% Test: 65.36%\n",
      "Epoch: 24, Loss: 1.2609, Train: 63.95%, Valid: 65.52% Test: 65.50%\n",
      "Epoch: 25, Loss: 1.2493, Train: 64.10%, Valid: 65.58% Test: 65.55%\n",
      "Epoch: 26, Loss: 1.2379, Train: 64.26%, Valid: 65.72% Test: 65.47%\n",
      "Epoch: 27, Loss: 1.2320, Train: 64.47%, Valid: 65.87% Test: 65.45%\n",
      "Epoch: 28, Loss: 1.2238, Train: 64.85%, Valid: 66.04% Test: 65.51%\n",
      "Epoch: 29, Loss: 1.2164, Train: 65.33%, Valid: 66.28% Test: 65.62%\n",
      "Epoch: 30, Loss: 1.2083, Train: 65.78%, Valid: 66.55% Test: 65.76%\n",
      "Epoch: 31, Loss: 1.1948, Train: 66.13%, Valid: 66.70% Test: 66.02%\n",
      "Epoch: 32, Loss: 1.1889, Train: 66.50%, Valid: 66.86% Test: 66.28%\n",
      "Epoch: 33, Loss: 1.1823, Train: 66.76%, Valid: 67.08% Test: 66.51%\n",
      "Epoch: 34, Loss: 1.1760, Train: 66.98%, Valid: 67.22% Test: 66.82%\n",
      "Epoch: 35, Loss: 1.1743, Train: 67.16%, Valid: 67.39% Test: 66.97%\n",
      "Epoch: 36, Loss: 1.1664, Train: 67.35%, Valid: 67.50% Test: 67.16%\n",
      "Epoch: 37, Loss: 1.1601, Train: 67.49%, Valid: 67.56% Test: 67.28%\n",
      "Epoch: 38, Loss: 1.1543, Train: 67.62%, Valid: 67.69% Test: 67.29%\n",
      "Epoch: 39, Loss: 1.1524, Train: 67.74%, Valid: 67.77% Test: 67.30%\n",
      "Epoch: 40, Loss: 1.1439, Train: 67.86%, Valid: 67.78% Test: 67.37%\n",
      "Epoch: 41, Loss: 1.1386, Train: 68.02%, Valid: 67.90% Test: 67.49%\n",
      "Epoch: 42, Loss: 1.1343, Train: 68.22%, Valid: 68.07% Test: 67.48%\n",
      "Epoch: 43, Loss: 1.1285, Train: 68.39%, Valid: 68.17% Test: 67.45%\n",
      "Epoch: 44, Loss: 1.1259, Train: 68.52%, Valid: 68.27% Test: 67.55%\n",
      "Epoch: 45, Loss: 1.1236, Train: 68.62%, Valid: 68.33% Test: 67.60%\n",
      "Epoch: 46, Loss: 1.1151, Train: 68.75%, Valid: 68.30% Test: 67.62%\n",
      "Epoch: 47, Loss: 1.1105, Train: 68.82%, Valid: 68.30% Test: 67.60%\n",
      "Epoch: 48, Loss: 1.1085, Train: 68.91%, Valid: 68.35% Test: 67.57%\n",
      "Epoch: 49, Loss: 1.1099, Train: 69.03%, Valid: 68.33% Test: 67.50%\n",
      "Epoch: 50, Loss: 1.1039, Train: 69.15%, Valid: 68.37% Test: 67.46%\n",
      "Epoch: 51, Loss: 1.0974, Train: 69.23%, Valid: 68.45% Test: 67.40%\n",
      "Epoch: 52, Loss: 1.0968, Train: 69.32%, Valid: 68.44% Test: 67.42%\n",
      "Epoch: 53, Loss: 1.0938, Train: 69.40%, Valid: 68.53% Test: 67.47%\n",
      "Epoch: 54, Loss: 1.0878, Train: 69.45%, Valid: 68.53% Test: 67.64%\n",
      "Epoch: 55, Loss: 1.0861, Train: 69.52%, Valid: 68.62% Test: 67.76%\n",
      "Epoch: 56, Loss: 1.0803, Train: 69.59%, Valid: 68.63% Test: 67.88%\n",
      "Epoch: 57, Loss: 1.0773, Train: 69.66%, Valid: 68.65% Test: 67.81%\n",
      "Epoch: 58, Loss: 1.0766, Train: 69.76%, Valid: 68.72% Test: 67.73%\n",
      "Epoch: 59, Loss: 1.0739, Train: 69.82%, Valid: 68.81% Test: 67.67%\n",
      "Epoch: 60, Loss: 1.0684, Train: 69.88%, Valid: 68.90% Test: 67.73%\n",
      "Epoch: 61, Loss: 1.0667, Train: 69.93%, Valid: 69.01% Test: 67.93%\n",
      "Epoch: 62, Loss: 1.0677, Train: 70.01%, Valid: 69.04% Test: 67.93%\n",
      "Epoch: 63, Loss: 1.0645, Train: 70.01%, Valid: 69.02% Test: 67.77%\n",
      "Epoch: 64, Loss: 1.0602, Train: 70.08%, Valid: 68.98% Test: 67.63%\n",
      "Epoch: 65, Loss: 1.0565, Train: 70.15%, Valid: 68.91% Test: 67.44%\n",
      "Epoch: 66, Loss: 1.0527, Train: 70.26%, Valid: 68.90% Test: 67.42%\n",
      "Epoch: 67, Loss: 1.0506, Train: 70.34%, Valid: 68.98% Test: 67.54%\n",
      "Epoch: 68, Loss: 1.0506, Train: 70.39%, Valid: 69.04% Test: 67.62%\n",
      "Epoch: 69, Loss: 1.0444, Train: 70.47%, Valid: 69.19% Test: 67.84%\n",
      "Epoch: 70, Loss: 1.0455, Train: 70.57%, Valid: 69.29% Test: 67.98%\n",
      "Epoch: 71, Loss: 1.0406, Train: 70.58%, Valid: 69.20% Test: 67.90%\n",
      "Epoch: 72, Loss: 1.0408, Train: 70.56%, Valid: 69.24% Test: 67.85%\n",
      "Epoch: 73, Loss: 1.0367, Train: 70.55%, Valid: 69.29% Test: 67.91%\n",
      "Epoch: 74, Loss: 1.0372, Train: 70.62%, Valid: 69.33% Test: 68.06%\n",
      "Epoch: 75, Loss: 1.0375, Train: 70.66%, Valid: 69.41% Test: 68.33%\n",
      "Epoch: 76, Loss: 1.0316, Train: 70.74%, Valid: 69.49% Test: 68.47%\n",
      "Epoch: 77, Loss: 1.0280, Train: 70.80%, Valid: 69.61% Test: 68.57%\n",
      "Epoch: 78, Loss: 1.0303, Train: 70.87%, Valid: 69.60% Test: 68.55%\n",
      "Epoch: 79, Loss: 1.0233, Train: 70.92%, Valid: 69.63% Test: 68.56%\n",
      "Epoch: 80, Loss: 1.0230, Train: 70.99%, Valid: 69.74% Test: 68.73%\n",
      "Epoch: 81, Loss: 1.0210, Train: 71.09%, Valid: 69.73% Test: 68.83%\n",
      "Epoch: 82, Loss: 1.0181, Train: 71.14%, Valid: 69.77% Test: 68.74%\n",
      "Epoch: 83, Loss: 1.0167, Train: 71.17%, Valid: 69.73% Test: 68.72%\n",
      "Epoch: 84, Loss: 1.0135, Train: 71.24%, Valid: 69.69% Test: 68.52%\n",
      "Epoch: 85, Loss: 1.0104, Train: 71.26%, Valid: 69.65% Test: 68.37%\n",
      "Epoch: 86, Loss: 1.0134, Train: 71.34%, Valid: 69.60% Test: 68.30%\n",
      "Epoch: 87, Loss: 1.0097, Train: 71.44%, Valid: 69.57% Test: 68.31%\n",
      "Epoch: 88, Loss: 1.0078, Train: 71.51%, Valid: 69.66% Test: 68.35%\n",
      "Epoch: 89, Loss: 1.0094, Train: 71.57%, Valid: 69.68% Test: 68.43%\n",
      "Epoch: 90, Loss: 1.0084, Train: 71.60%, Valid: 69.80% Test: 68.50%\n",
      "Epoch: 91, Loss: 1.0060, Train: 71.67%, Valid: 69.88% Test: 68.59%\n",
      "Epoch: 92, Loss: 1.0018, Train: 71.72%, Valid: 69.92% Test: 68.54%\n",
      "Epoch: 93, Loss: 0.9991, Train: 71.76%, Valid: 69.87% Test: 68.56%\n",
      "Epoch: 94, Loss: 0.9959, Train: 71.79%, Valid: 69.86% Test: 68.53%\n",
      "Epoch: 95, Loss: 0.9955, Train: 71.71%, Valid: 69.66% Test: 68.34%\n",
      "Epoch: 96, Loss: 0.9962, Train: 71.74%, Valid: 69.57% Test: 68.12%\n",
      "Epoch: 97, Loss: 0.9928, Train: 71.72%, Valid: 69.50% Test: 68.09%\n",
      "Epoch: 98, Loss: 0.9915, Train: 71.76%, Valid: 69.56% Test: 68.15%\n",
      "Epoch: 99, Loss: 0.9893, Train: 71.89%, Valid: 69.64% Test: 68.28%\n",
      "Epoch: 100, Loss: 0.9902, Train: 72.01%, Valid: 69.61% Test: 68.21%\n",
      "Best model: Train: 71.72%, Valid: 69.92% Test: 68.54%\n"
     ]
    }
   ],
   "source": [
    "# Use the same parameters for a full-batch training\n",
    "args = {\n",
    "    'device': device,\n",
    "    'num_layers': 2,\n",
    "    'hidden_dim': 128,\n",
    "    'dropout': 0.5,\n",
    "    'lr': 0.01,\n",
    "    'epochs': 100,\n",
    "}\n",
    "\n",
    "all_model = SAGE(data.num_features, args['hidden_dim'],\n",
    "            dataset.num_classes, args['num_layers'],\n",
    "            args['dropout']).to(device)\n",
    "all_model.reset_parameters()\n",
    "\n",
    "optimizer = torch.optim.Adam(all_model.parameters(), lr=args['lr'])\n",
    "loss_fn = F.nll_loss\n",
    "\n",
    "best_all_model = None\n",
    "best_valid_acc = 0\n",
    "\n",
    "all_results = []\n",
    "\n",
    "for epoch in range(1, 1 + args[\"epochs\"]):\n",
    "    loss = train(all_model, data, train_loader, train_idx, optimizer, loss_fn, mode=\"all\")\n",
    "    result = test(all_model, data, all_loader, split_idx, evaluator, mode=\"all\")\n",
    "    all_results.append(result)\n",
    "    train_acc, valid_acc, test_acc = result\n",
    "    if valid_acc > best_valid_acc:\n",
    "        best_valid_acc = valid_acc\n",
    "        best_all_model = copy.deepcopy(all_model)\n",
    "    print(f'Epoch: {epoch:02d}, '\n",
    "          f'Loss: {loss:.4f}, '\n",
    "          f'Train: {100 * train_acc:.2f}%, '\n",
    "          f'Valid: {100 * valid_acc:.2f}% '\n",
    "          f'Test: {100 * test_acc:.2f}%')\n",
    "best_result = test(best_all_model, data, all_loader, split_idx, evaluator, mode=\"all\")\n",
    "train_acc, valid_acc, test_acc = best_result\n",
    "print(f'Best model: '\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * valid_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "NrECcOQQSZo1"
   },
   "source": [
    "## Visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "sh_qvSG1SV63"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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E66sBCAxSeukiIiIOE0lpR5bWUmVR5taiYiIxAOVlHpsVRVBj94SERGReBDT38jGmInGmI3GmC3GmDmNfP6/jTHrjTFfGmPeN8b0iWWeQ6qqIpiokiIiIhIPYvYb2RjjBh4FJgFDgRnGmKENTlsFZFlrRwKLgAdiladJAtWEPW5HI4iIiEhULIcNTgK2WGu3WWurgYXA1PonWGuXWGsral7+C+gZwzyH5KoKEvZqEV4REYmumpqZmcmoUaM44YQTDrkTcFN3QR43btxB99pZu3Zt3fosnTp1om/fvmRmZnLuuece9s/wu9/97nutIuu0WJaUHkBevdc7a44dyHXAW419whgz0xiTbYzJzs/Pb8aI+3NVBYl4PTG7voiItB61e/esWbOG3/72t9x+++0HPb+pJeVQRowYwerVq1m9ejVTpkzhwQcfZPXq1d/ZhLApWntJiYthA2PMD4Es4MzGPm+tfRx4HKKLucUqh7s6RCQlOVaXFxGRI/HWHNiztnmvecwImDSvyaf7/f66jfnKysqYOnUqRUVFBINB7r33XqZOncqcOXPYunUrmZmZjB8/ngcffJD777+fF154AZfLxaRJk5g3L/o9X375ZW688UaKi4t58sknOf3005ucZd68ebzyyisEAgEuu+wy7rzzTkpLS/mP//gPdu/eTTgc5u677yYvL4+9e/dy+umn061btyMqOU6LZUnZBdRftrVnzbH9GGPOBf4fcKa1tiqGeQ7JXR2G9EQnI4iISJyoXRY/EAjwzTff8MEHHwDg8/l49dVXSUtLo6CggDFjxjBlyhTmzZvHunXr6nZOfuutt3j99df57LPPSE5O3m/vnlAoxOeff87ixYuZO3dukwvE4sWL2bFjB5999hnWWs4//3w++eQT8vLyyMjI4K23ojckSkpKaN++Pf/zP//D8uXL6dChdS5SGsuS8gUwwBjTl2g5mQ5cXv8EY8zxwJ+BidbavTHM0iSe6jBhn/fQJ4qISMs5jBGP5lR7uwfg008/5aqrrmLdunVYa7njjjtYtmwZLpeLXbt28e23337n69977z2uvfZakpOjI/SdOnWq+1ztXjyjR48mNze3yZneeecd3nrrLY4//nggOqqzadMmTj75ZObMmcOcOXOYPHkyY8eOPdIfO67ErKRYa0PGmJuAtwE38JS19itjzD1AtrX2DeBBIBV4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\n",
      "text/plain": [
       "<Figure size 648x504 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "batch_results = np.array(batch_results)\n",
    "all_results = np.array(all_results)\n",
    "\n",
    "x = np.arange(1, 101)\n",
    "\n",
    "plt.figure(figsize=(9, 7))\n",
    "\n",
    "plt.plot(x, batch_results[:, 1], label=\"Batch Validation\")\n",
    "plt.plot(x, batch_results[:, 2], label=\"Batch Test\")\n",
    "plt.plot(x, all_results[:, 1], label=\"All Validation\")\n",
    "plt.plot(x, all_results[:, 2], label=\"All Test\")\n",
    "plt.title('Model Accuracy')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "WFb2OAvOSn_O"
   },
   "source": [
    "# 2 Neighbor Sampling with Different Ratios\n",
    "\n",
    "Now we will implement a simplified version of Neighbor Sampling by using DeepSNAP and NetworkX, and train models with different neighborhood sampling ratios.\n",
    "\n",
    "To make the experiments faster, we will use the Cora graph here."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "P9U0F7bnSz9u"
   },
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "PUF4on-fSxcq"
   },
   "outputs": [],
   "source": [
    "import copy\n",
    "import torch\n",
    "import random\n",
    "import numpy as np\n",
    "import networkx as nx\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "from torch_geometric.nn import SAGEConv\n",
    "from torch.utils.data import DataLoader\n",
    "from torch_geometric.datasets import Planetoid\n",
    "from torch.nn import Sequential, Linear, ReLU\n",
    "from deepsnap.dataset import GraphDataset\n",
    "from deepsnap.graph import Graph\n",
    "\n",
    "pyg_dataset = Planetoid('./tmp/cora', \"Cora\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "qw6k-KdFTEYw"
   },
   "source": [
    "## GNN Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "PvUlNi2TS09i"
   },
   "outputs": [],
   "source": [
    "class GNN(torch.nn.Module):\n",
    "    def __init__(self, input_dim, hidden_dim, output_dim, args):\n",
    "        super(GNN, self).__init__()\n",
    "        self.dropout = args['dropout']\n",
    "        self.num_layers = args['num_layers']\n",
    "\n",
    "        self.convs = nn.ModuleList()\n",
    "        self.bns = nn.ModuleList()\n",
    "\n",
    "        self.convs.append(SAGEConv(input_dim, hidden_dim))\n",
    "        self.bns.append(nn.BatchNorm1d(hidden_dim))\n",
    "\n",
    "        for l in range(self.num_layers - 2):\n",
    "            self.convs.append(SAGEConv(hidden_dim, hidden_dim))\n",
    "            self.bns.append(nn.BatchNorm1d(hidden_dim))\n",
    "        self.convs.append(SAGEConv(hidden_dim, hidden_dim))\n",
    "\n",
    "        self.post_mp = nn.Linear(hidden_dim, output_dim)\n",
    "\n",
    "    def forward(self, data, mode=\"batch\"):\n",
    "        if mode == \"batch\":\n",
    "            edge_indices, x = data\n",
    "            for i in range(len(self.convs) - 1):\n",
    "                edge_index = edge_indices[i]\n",
    "                x = self.convs[i](x, edge_index)\n",
    "                x = self.bns[i](x)\n",
    "                x = F.relu(x)\n",
    "                x = F.dropout(x, p=self.dropout, training=self.training)\n",
    "            x = self.convs[-1](x, edge_indices[len(self.convs) - 1])\n",
    "        else:\n",
    "            x, edge_index = data.node_feature, data.edge_index\n",
    "            for i in range(len(self.convs) - 1):\n",
    "                x = self.convs[i](x, edge_index)\n",
    "                x = self.bns[i](x)\n",
    "                x = F.relu(x)\n",
    "                x = F.dropout(x, p=self.dropout, training=self.training)\n",
    "            x = self.convs[-1](x, edge_index)\n",
    "        x = self.post_mp(x)\n",
    "        x = F.log_softmax(x, dim=1)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Ulp1A3evcJ-I"
   },
   "source": [
    "## Neighbor Sampling\n",
    "\n",
    "Here we implement functions that will sample neighbors by using DeepSNAP and NetworkX.\n",
    "\n",
    "Notice that node classification task on Cora is a semi-supervised classification task, here we keep all the labeled training nodes (140 nodes) by setting the last ratio to 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "LI4qHkE4cQOh"
   },
   "outputs": [],
   "source": [
    "def sample_neighbors(nodes, G, ratio, all_nodes):\n",
    "    # This fuction takes a set of nodes, a NetworkX graph G and neighbor sampling ratio.\n",
    "    # It will return sampled neighbors (unioned with input nodes) and edges between \n",
    "    neighbors = set()\n",
    "    edges = []\n",
    "    for node in nodes:\n",
    "        neighbors_list = list(nx.neighbors(G, node))\n",
    "\n",
    "        # We only sample the (ratio * number of neighbors) neighbors\n",
    "        num = int(len(neighbors_list) * ratio)\n",
    "        if num > 0:\n",
    "            # Random shuffle the neighbors\n",
    "            random.shuffle(neighbors_list)\n",
    "            neighbors_list = neighbors_list[:num]\n",
    "            for neighbor in neighbors_list:\n",
    "                # Add neighbors\n",
    "                neighbors.add(neighbor)\n",
    "                edges.append((neighbor, node))\n",
    "    return neighbors, neighbors.union(all_nodes), edges\n",
    "\n",
    "def nodes_to_tensor(nodes):\n",
    "    # This function transform a set of nodes to node index tensor\n",
    "    node_label_index = torch.tensor(list(nodes), dtype=torch.long)\n",
    "    return node_label_index\n",
    "\n",
    "def edges_to_tensor(edges):\n",
    "    # This function transform a set of edges to edge index tensor\n",
    "    edge_index = torch.tensor(list(edges), dtype=torch.long)\n",
    "    edge_index = torch.cat([edge_index, torch.flip(edge_index, [1])], dim=0)\n",
    "    edge_index = edge_index.permute(1, 0)\n",
    "    return edge_index\n",
    "\n",
    "def relable(nodes, labeled_nodes, edges_list):\n",
    "    # Relable the nodes, labeled_nodes and edges_list\n",
    "    relabled_edges_list = []\n",
    "    sorted_nodes = sorted(nodes)\n",
    "    node_mapping = {node : i for i, node in enumerate(sorted_nodes)}\n",
    "    for orig_edges in edges_list:\n",
    "        relabeled_edges = []\n",
    "        for edge in orig_edges:\n",
    "            relabeled_edges.append((node_mapping[edge[0]], node_mapping[edge[1]]))\n",
    "        relabled_edges_list.append(relabeled_edges)\n",
    "    relabeled_labeled_nodes = [node_mapping[node] for node in labeled_nodes]\n",
    "    relabeled_nodes = [node_mapping[node] for node in nodes]\n",
    "    return relabled_edges_list, relabeled_nodes, relabeled_labeled_nodes\n",
    "\n",
    "def neighbor_sampling(graph, K=2, ratios=(0.1, 0.1, 0.1)):\n",
    "    # This function takes a DeepSNAP graph, K the number of GNN layers, and neighbor \n",
    "    # sampling ratios for each layer. This function returns relabeled node feature, \n",
    "    # edge indices and node_label_index\n",
    "\n",
    "    assert K + 1 == len(ratios)\n",
    "\n",
    "    labeled_nodes = graph.node_label_index.tolist()\n",
    "    random.shuffle(labeled_nodes)\n",
    "    num = int(len(labeled_nodes) * ratios[-1])\n",
    "    if num > 0:\n",
    "        labeled_nodes = labeled_nodes[:num]\n",
    "    nodes_list = [set(labeled_nodes)]\n",
    "    edges_list = []\n",
    "    all_nodes = labeled_nodes\n",
    "    for k in range(K):\n",
    "        # Get nodes and edges from the previous layer\n",
    "        nodes, all_nodes, edges = \\\n",
    "            sample_neighbors(nodes_list[-1], graph.G, ratios[len(ratios) - k - 2], all_nodes)\n",
    "        nodes_list.append(nodes)\n",
    "        edges_list.append(edges)\n",
    "    \n",
    "    # Reverse the lists\n",
    "    nodes_list.reverse()\n",
    "    edges_list.reverse()\n",
    "\n",
    "    relabled_edges_list, relabeled_all_nodes, relabeled_labeled_nodes = \\\n",
    "        relable(all_nodes, labeled_nodes, edges_list)\n",
    "\n",
    "    node_index = nodes_to_tensor(relabeled_all_nodes)\n",
    "    # All node features that will be used\n",
    "    node_feature = graph.node_feature[node_index]\n",
    "    edge_indices = [edges_to_tensor(edges) for edges in relabled_edges_list]\n",
    "    node_label_index = nodes_to_tensor(relabeled_labeled_nodes)\n",
    "    log = \"Sampled {} nodes, {} edges, {} labeled nodes\"\n",
    "    print(log.format(node_feature.shape[0], edge_indices[0].shape[1] // 2, node_label_index.shape[0]))\n",
    "    return node_feature, edge_indices, node_label_index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ooy6Hcf7TIhI"
   },
   "source": [
    "## Training and Testing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "id": "iSmZhpzPTGPY"
   },
   "outputs": [],
   "source": [
    "def train(train_graphs, val_graphs, args, model, optimizer, mode=\"batch\"):\n",
    "    best_val = 0\n",
    "    best_model = None\n",
    "    accs = []\n",
    "    graph_train = train_graphs[0]\n",
    "    graph_train.to(args['device'])\n",
    "    for epoch in range(1, 1 + args['epochs']):\n",
    "        model.train()\n",
    "        optimizer.zero_grad()\n",
    "        if mode == \"batch\":\n",
    "            node_feature, edge_indices, node_label_index = neighbor_sampling(graph_train, args['num_layers'], args['ratios'])\n",
    "            node_feature = node_feature.to(args['device'])\n",
    "            node_label_index = node_label_index.to(args['device'])\n",
    "            for i in range(len(edge_indices)):\n",
    "                edge_indices[i] = edge_indices[i].to(args['device'])\n",
    "            pred = model([edge_indices, node_feature])\n",
    "            pred = pred[node_label_index]\n",
    "            label = graph_train.node_label[node_label_index]\n",
    "        elif mode == \"community\":\n",
    "            graph = random.choice(train_graphs)\n",
    "            graph = graph.to(args['device'])\n",
    "            pred = model(graph, mode=\"all\")\n",
    "            pred = pred[graph.node_label_index]\n",
    "            label = graph.node_label[graph.node_label_index]\n",
    "        else:\n",
    "            pred = model(graph_train, mode=\"all\")\n",
    "            label = graph_train.node_label\n",
    "            pred = pred[graph_train.node_label_index]\n",
    "        loss = F.nll_loss(pred, label)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "        train_acc, val_acc, test_acc = test(val_graphs, model)\n",
    "        accs.append((train_acc, val_acc, test_acc))\n",
    "        if val_acc > best_val:\n",
    "            best_val = val_acc\n",
    "            best_model = copy.deepcopy(model)\n",
    "        print(f'Epoch: {epoch:02d}, '\n",
    "              f'Loss: {loss:.4f}, '\n",
    "              f'Train: {100 * train_acc:.2f}%, '\n",
    "              f'Valid: {100 * val_acc:.2f}% '\n",
    "              f'Test: {100 * test_acc:.2f}%')\n",
    "    return best_model, accs\n",
    "\n",
    "def test(graphs, model):\n",
    "    model.eval()\n",
    "    accs = []\n",
    "    for graph in graphs:\n",
    "        graph = graph.to(args['device'])\n",
    "        pred = model(graph, mode=\"all\")\n",
    "        label = graph.node_label\n",
    "        pred = pred[graph.node_label_index].max(1)[1]\n",
    "        acc = pred.eq(label).sum().item()\n",
    "        acc /= len(label)\n",
    "        accs.append(acc)\n",
    "    return accs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "id": "HV7i0v0ETKzf"
   },
   "outputs": [],
   "source": [
    "args = {\n",
    "    'device': torch.device('cuda' if torch.cuda.is_available() else 'cpu'),\n",
    "    'dropout': 0.5,\n",
    "    'num_layers': 2,\n",
    "    'hidden_size': 64,\n",
    "    'lr': 0.005,\n",
    "    'epochs': 50,\n",
    "    'ratios': (0.8, 0.8, 1),\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rLpRYKbnTQnj"
   },
   "source": [
    "## Full-Batch Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "id": "pMGGjbJBTOo1"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Epoch: 01, Loss: 2.0117, Train: 72.86%, Valid: 39.60% Test: 39.50%\n",
      "Epoch: 02, Loss: 1.1633, Train: 99.29%, Valid: 61.80% Test: 61.30%\n",
      "Epoch: 03, Loss: 0.6134, Train: 100.00%, Valid: 69.40% Test: 67.30%\n",
      "Epoch: 04, Loss: 0.3039, Train: 100.00%, Valid: 71.00% Test: 70.50%\n",
      "Epoch: 05, Loss: 0.1570, Train: 100.00%, Valid: 71.00% Test: 71.50%\n",
      "Epoch: 06, Loss: 0.0682, Train: 100.00%, Valid: 72.20% Test: 72.00%\n",
      "Epoch: 07, Loss: 0.0482, Train: 100.00%, Valid: 73.20% Test: 72.00%\n",
      "Epoch: 08, Loss: 0.0232, Train: 100.00%, Valid: 72.80% Test: 72.90%\n",
      "Epoch: 09, Loss: 0.0106, Train: 100.00%, Valid: 73.00% Test: 73.10%\n",
      "Epoch: 10, Loss: 0.0093, Train: 100.00%, Valid: 73.00% Test: 73.10%\n",
      "Epoch: 11, Loss: 0.0046, Train: 100.00%, Valid: 73.00% Test: 72.90%\n",
      "Epoch: 12, Loss: 0.0031, Train: 100.00%, Valid: 72.20% Test: 73.10%\n",
      "Epoch: 13, Loss: 0.0017, Train: 100.00%, Valid: 72.00% Test: 72.70%\n",
      "Epoch: 14, Loss: 0.0007, Train: 100.00%, Valid: 72.00% Test: 73.00%\n",
      "Epoch: 15, Loss: 0.0033, Train: 100.00%, Valid: 71.60% Test: 73.10%\n",
      "Epoch: 16, Loss: 0.0034, Train: 100.00%, Valid: 71.80% Test: 73.40%\n",
      "Epoch: 17, Loss: 0.0009, Train: 100.00%, Valid: 71.80% Test: 73.20%\n",
      "Epoch: 18, Loss: 0.0003, Train: 100.00%, Valid: 71.40% Test: 73.20%\n",
      "Epoch: 19, Loss: 0.0010, Train: 100.00%, Valid: 71.00% Test: 73.00%\n",
      "Epoch: 20, Loss: 0.0003, Train: 100.00%, Valid: 71.20% Test: 72.70%\n",
      "Epoch: 21, Loss: 0.0049, Train: 100.00%, Valid: 71.00% Test: 72.70%\n",
      "Epoch: 22, Loss: 0.0002, Train: 100.00%, Valid: 71.20% Test: 72.80%\n",
      "Epoch: 23, Loss: 0.0002, Train: 100.00%, Valid: 70.80% Test: 73.10%\n",
      "Epoch: 24, Loss: 0.0014, Train: 100.00%, Valid: 70.60% Test: 73.00%\n",
      "Epoch: 25, Loss: 0.0020, Train: 100.00%, Valid: 70.80% Test: 72.90%\n",
      "Epoch: 26, Loss: 0.0002, Train: 100.00%, Valid: 71.00% Test: 72.80%\n",
      "Epoch: 27, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.00%\n",
      "Epoch: 28, Loss: 0.0002, Train: 100.00%, Valid: 71.00% Test: 73.00%\n",
      "Epoch: 29, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.00%\n",
      "Epoch: 30, Loss: 0.0001, Train: 100.00%, Valid: 70.80% Test: 72.90%\n",
      "Epoch: 31, Loss: 0.0002, Train: 100.00%, Valid: 70.80% Test: 73.00%\n",
      "Epoch: 32, Loss: 0.0001, Train: 100.00%, Valid: 70.80% Test: 73.00%\n",
      "Epoch: 33, Loss: 0.0002, Train: 100.00%, Valid: 70.60% Test: 73.00%\n",
      "Epoch: 34, Loss: 0.0000, Train: 100.00%, Valid: 70.60% Test: 73.10%\n",
      "Epoch: 35, Loss: 0.0000, Train: 100.00%, Valid: 70.60% Test: 73.10%\n",
      "Epoch: 36, Loss: 0.0000, Train: 100.00%, Valid: 70.60% Test: 73.00%\n",
      "Epoch: 37, Loss: 0.0000, Train: 100.00%, Valid: 70.40% Test: 72.90%\n",
      "Epoch: 38, Loss: 0.0000, Train: 100.00%, Valid: 70.40% Test: 73.00%\n",
      "Epoch: 39, Loss: 0.0001, Train: 100.00%, Valid: 70.40% Test: 73.00%\n",
      "Epoch: 40, Loss: 0.0001, Train: 100.00%, Valid: 70.40% Test: 73.00%\n",
      "Epoch: 41, Loss: 0.0001, Train: 100.00%, Valid: 70.40% Test: 73.00%\n",
      "Epoch: 42, Loss: 0.0000, Train: 100.00%, Valid: 70.40% Test: 73.00%\n",
      "Epoch: 43, Loss: 0.0000, Train: 100.00%, Valid: 70.40% Test: 72.90%\n",
      "Epoch: 44, Loss: 0.0001, Train: 100.00%, Valid: 70.40% Test: 72.90%\n",
      "Epoch: 45, Loss: 0.0001, Train: 100.00%, Valid: 70.40% Test: 72.80%\n",
      "Epoch: 46, Loss: 0.0001, Train: 100.00%, Valid: 70.20% Test: 72.80%\n",
      "Epoch: 47, Loss: 0.0001, Train: 100.00%, Valid: 70.20% Test: 72.80%\n",
      "Epoch: 48, Loss: 0.0004, Train: 100.00%, Valid: 70.40% Test: 72.80%\n",
      "Epoch: 49, Loss: 0.0001, Train: 100.00%, Valid: 70.40% Test: 72.80%\n",
      "Epoch: 50, Loss: 0.0000, Train: 100.00%, Valid: 70.40% Test: 72.80%\n",
      "Best model: Train: 100.00%, Valid: 73.20% Test: 72.00%\n"
     ]
    }
   ],
   "source": [
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "\n",
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "graphs = [graph_train, graph_val, graph_test]\n",
    "all_best_model, all_accs = train(graphs, graphs, args, model, optimizer, mode=\"all\")\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], all_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "JWkGiwB6Thr4"
   },
   "source": [
    "## Sampling with Ratios 0.8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "id": "yWusJ9u3Tfhv"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Sampled 1346 nodes, 2033 edges, 140 labeled nodes\n",
      "Epoch: 01, Loss: 2.0139, Train: 22.86%, Valid: 14.40% Test: 13.40%\n",
      "Sampled 1321 nodes, 2024 edges, 140 labeled nodes\n",
      "Epoch: 02, Loss: 1.6252, Train: 27.86%, Valid: 11.60% Test: 11.40%\n",
      "Sampled 1258 nodes, 1862 edges, 140 labeled nodes\n",
      "Epoch: 03, Loss: 1.4089, Train: 41.43%, Valid: 12.00% Test: 12.50%\n",
      "Sampled 1292 nodes, 1944 edges, 140 labeled nodes\n",
      "Epoch: 04, Loss: 1.1107, Train: 71.43%, Valid: 15.40% Test: 16.00%\n",
      "Sampled 1300 nodes, 1940 edges, 140 labeled nodes\n",
      "Epoch: 05, Loss: 0.8323, Train: 88.57%, Valid: 20.20% Test: 22.50%\n",
      "Sampled 1275 nodes, 1976 edges, 140 labeled nodes\n",
      "Epoch: 06, Loss: 0.6372, Train: 93.57%, Valid: 28.00% Test: 28.90%\n",
      "Sampled 1344 nodes, 2059 edges, 140 labeled nodes\n",
      "Epoch: 07, Loss: 0.5225, Train: 97.86%, Valid: 34.20% Test: 33.90%\n",
      "Sampled 1315 nodes, 1960 edges, 140 labeled nodes\n",
      "Epoch: 08, Loss: 0.3700, Train: 98.57%, Valid: 38.60% Test: 37.80%\n",
      "Sampled 1317 nodes, 2012 edges, 140 labeled nodes\n",
      "Epoch: 09, Loss: 0.2558, Train: 98.57%, Valid: 42.00% Test: 42.00%\n",
      "Sampled 1319 nodes, 2032 edges, 140 labeled nodes\n",
      "Epoch: 10, Loss: 0.1732, Train: 98.57%, Valid: 45.40% Test: 44.30%\n",
      "Sampled 1316 nodes, 1959 edges, 140 labeled nodes\n",
      "Epoch: 11, Loss: 0.1869, Train: 98.57%, Valid: 45.60% Test: 46.40%\n",
      "Sampled 1317 nodes, 1984 edges, 140 labeled nodes\n",
      "Epoch: 12, Loss: 0.1405, Train: 99.29%, Valid: 48.20% Test: 48.50%\n",
      "Sampled 1339 nodes, 1993 edges, 140 labeled nodes\n",
      "Epoch: 13, Loss: 0.1490, Train: 99.29%, Valid: 49.40% Test: 49.90%\n",
      "Sampled 1316 nodes, 1999 edges, 140 labeled nodes\n",
      "Epoch: 14, Loss: 0.0749, Train: 99.29%, Valid: 51.40% Test: 51.10%\n",
      "Sampled 1308 nodes, 1990 edges, 140 labeled nodes\n",
      "Epoch: 15, Loss: 0.0730, Train: 99.29%, Valid: 51.80% Test: 52.00%\n",
      "Sampled 1336 nodes, 2040 edges, 140 labeled nodes\n",
      "Epoch: 16, Loss: 0.0648, Train: 100.00%, Valid: 53.20% Test: 52.90%\n",
      "Sampled 1310 nodes, 1978 edges, 140 labeled nodes\n",
      "Epoch: 17, Loss: 0.0887, Train: 100.00%, Valid: 52.80% Test: 53.70%\n",
      "Sampled 1310 nodes, 2011 edges, 140 labeled nodes\n",
      "Epoch: 18, Loss: 0.0530, Train: 100.00%, Valid: 53.20% Test: 53.80%\n",
      "Sampled 1304 nodes, 1991 edges, 140 labeled nodes\n",
      "Epoch: 19, Loss: 0.0332, Train: 100.00%, Valid: 53.60% Test: 54.60%\n",
      "Sampled 1314 nodes, 1978 edges, 140 labeled nodes\n",
      "Epoch: 20, Loss: 0.0223, Train: 100.00%, Valid: 53.20% Test: 54.20%\n",
      "Sampled 1345 nodes, 2023 edges, 140 labeled nodes\n",
      "Epoch: 21, Loss: 0.0549, Train: 100.00%, Valid: 53.40% Test: 54.00%\n",
      "Sampled 1345 nodes, 2033 edges, 140 labeled nodes\n",
      "Epoch: 22, Loss: 0.0334, Train: 100.00%, Valid: 53.20% Test: 53.80%\n",
      "Sampled 1335 nodes, 2001 edges, 140 labeled nodes\n",
      "Epoch: 23, Loss: 0.0231, Train: 100.00%, Valid: 52.20% Test: 53.80%\n",
      "Sampled 1328 nodes, 2027 edges, 140 labeled nodes\n",
      "Epoch: 24, Loss: 0.0379, Train: 100.00%, Valid: 51.60% Test: 53.20%\n",
      "Sampled 1267 nodes, 1916 edges, 140 labeled nodes\n",
      "Epoch: 25, Loss: 0.0141, Train: 100.00%, Valid: 51.40% Test: 53.10%\n",
      "Sampled 1311 nodes, 1972 edges, 140 labeled nodes\n",
      "Epoch: 26, Loss: 0.0136, Train: 100.00%, Valid: 51.40% Test: 53.10%\n",
      "Sampled 1339 nodes, 1990 edges, 140 labeled nodes\n",
      "Epoch: 27, Loss: 0.0072, Train: 100.00%, Valid: 51.40% Test: 53.00%\n",
      "Sampled 1332 nodes, 2033 edges, 140 labeled nodes\n",
      "Epoch: 28, Loss: 0.0243, Train: 100.00%, Valid: 50.60% Test: 52.30%\n",
      "Sampled 1332 nodes, 2004 edges, 140 labeled nodes\n",
      "Epoch: 29, Loss: 0.0224, Train: 100.00%, Valid: 50.40% Test: 51.90%\n",
      "Sampled 1311 nodes, 2012 edges, 140 labeled nodes\n",
      "Epoch: 30, Loss: 0.0078, Train: 100.00%, Valid: 50.00% Test: 51.80%\n",
      "Sampled 1318 nodes, 1993 edges, 140 labeled nodes\n",
      "Epoch: 31, Loss: 0.0048, Train: 100.00%, Valid: 49.00% Test: 50.80%\n",
      "Sampled 1278 nodes, 1985 edges, 140 labeled nodes\n",
      "Epoch: 32, Loss: 0.0112, Train: 100.00%, Valid: 48.40% Test: 50.50%\n",
      "Sampled 1300 nodes, 1953 edges, 140 labeled nodes\n",
      "Epoch: 33, Loss: 0.0646, Train: 100.00%, Valid: 48.60% Test: 51.20%\n",
      "Sampled 1338 nodes, 1971 edges, 140 labeled nodes\n",
      "Epoch: 34, Loss: 0.0186, Train: 100.00%, Valid: 48.60% Test: 51.10%\n",
      "Sampled 1300 nodes, 1938 edges, 140 labeled nodes\n",
      "Epoch: 35, Loss: 0.0197, Train: 100.00%, Valid: 48.40% Test: 51.00%\n",
      "Sampled 1330 nodes, 2075 edges, 140 labeled nodes\n",
      "Epoch: 36, Loss: 0.0100, Train: 100.00%, Valid: 48.00% Test: 50.70%\n",
      "Sampled 1292 nodes, 1956 edges, 140 labeled nodes\n",
      "Epoch: 37, Loss: 0.0018, Train: 100.00%, Valid: 47.80% Test: 50.80%\n",
      "Sampled 1313 nodes, 2011 edges, 140 labeled nodes\n",
      "Epoch: 38, Loss: 0.0029, Train: 100.00%, Valid: 48.00% Test: 51.00%\n",
      "Sampled 1293 nodes, 1993 edges, 140 labeled nodes\n",
      "Epoch: 39, Loss: 0.0634, Train: 100.00%, Valid: 48.40% Test: 50.80%\n",
      "Sampled 1329 nodes, 2029 edges, 140 labeled nodes\n",
      "Epoch: 40, Loss: 0.0047, Train: 100.00%, Valid: 48.00% Test: 50.80%\n",
      "Sampled 1329 nodes, 2027 edges, 140 labeled nodes\n",
      "Epoch: 41, Loss: 0.0324, Train: 100.00%, Valid: 48.20% Test: 51.50%\n",
      "Sampled 1337 nodes, 2016 edges, 140 labeled nodes\n",
      "Epoch: 42, Loss: 0.0149, Train: 100.00%, Valid: 48.40% Test: 51.20%\n",
      "Sampled 1269 nodes, 1933 edges, 140 labeled nodes\n",
      "Epoch: 43, Loss: 0.0764, Train: 100.00%, Valid: 49.20% Test: 51.20%\n",
      "Sampled 1315 nodes, 1981 edges, 140 labeled nodes\n",
      "Epoch: 44, Loss: 0.0034, Train: 100.00%, Valid: 49.20% Test: 51.00%\n",
      "Sampled 1306 nodes, 1937 edges, 140 labeled nodes\n",
      "Epoch: 45, Loss: 0.0079, Train: 100.00%, Valid: 49.20% Test: 51.20%\n",
      "Sampled 1342 nodes, 2002 edges, 140 labeled nodes\n",
      "Epoch: 46, Loss: 0.0048, Train: 100.00%, Valid: 49.40% Test: 51.20%\n",
      "Sampled 1294 nodes, 1919 edges, 140 labeled nodes\n",
      "Epoch: 47, Loss: 0.0033, Train: 100.00%, Valid: 49.60% Test: 51.20%\n",
      "Sampled 1338 nodes, 2048 edges, 140 labeled nodes\n",
      "Epoch: 48, Loss: 0.0122, Train: 100.00%, Valid: 49.80% Test: 51.40%\n",
      "Sampled 1302 nodes, 1991 edges, 140 labeled nodes\n",
      "Epoch: 49, Loss: 0.0081, Train: 100.00%, Valid: 50.00% Test: 51.30%\n",
      "Sampled 1289 nodes, 1935 edges, 140 labeled nodes\n",
      "Epoch: 50, Loss: 0.0125, Train: 100.00%, Valid: 50.20% Test: 51.40%\n",
      "Best model: Train: 100.00%, Valid: 53.60% Test: 54.60%\n"
     ]
    }
   ],
   "source": [
    "args['ratios'] = (0.8, 0.8, 1)\n",
    "\n",
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "\n",
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "graphs = [graph_train, graph_val, graph_test]\n",
    "batch_best_model, batch_accs = train(graphs, graphs, args, model, optimizer)\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], batch_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "w_FjkNHDT4c6"
   },
   "source": [
    "## Sampling with Ratios 0.3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "id": "booJ6DASTjO4"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Sampled 381 nodes, 192 edges, 140 labeled nodes\n",
      "Epoch: 01, Loss: 2.0060, Train: 14.29%, Valid: 16.40% Test: 15.30%\n",
      "Sampled 419 nodes, 217 edges, 140 labeled nodes\n",
      "Epoch: 02, Loss: 1.9695, Train: 21.43%, Valid: 17.20% Test: 17.60%\n",
      "Sampled 439 nodes, 245 edges, 140 labeled nodes\n",
      "Epoch: 03, Loss: 1.9129, Train: 24.29%, Valid: 18.40% Test: 17.90%\n",
      "Sampled 418 nodes, 227 edges, 140 labeled nodes\n",
      "Epoch: 04, Loss: 1.9264, Train: 25.71%, Valid: 18.60% Test: 18.20%\n",
      "Sampled 410 nodes, 227 edges, 140 labeled nodes\n",
      "Epoch: 05, Loss: 1.8384, Train: 30.00%, Valid: 18.40% Test: 18.60%\n",
      "Sampled 377 nodes, 186 edges, 140 labeled nodes\n",
      "Epoch: 06, Loss: 1.8055, Train: 34.29%, Valid: 18.40% Test: 18.50%\n",
      "Sampled 413 nodes, 221 edges, 140 labeled nodes\n",
      "Epoch: 07, Loss: 1.8636, Train: 36.43%, Valid: 18.20% Test: 19.20%\n",
      "Sampled 411 nodes, 232 edges, 140 labeled nodes\n",
      "Epoch: 08, Loss: 1.7894, Train: 39.29%, Valid: 20.80% Test: 21.00%\n",
      "Sampled 424 nodes, 238 edges, 140 labeled nodes\n",
      "Epoch: 09, Loss: 1.8310, Train: 43.57%, Valid: 22.00% Test: 22.50%\n",
      "Sampled 448 nodes, 270 edges, 140 labeled nodes\n",
      "Epoch: 10, Loss: 1.8337, Train: 47.86%, Valid: 25.40% Test: 24.70%\n",
      "Sampled 373 nodes, 169 edges, 140 labeled nodes\n",
      "Epoch: 11, Loss: 1.6776, Train: 49.29%, Valid: 24.40% Test: 26.00%\n",
      "Sampled 442 nodes, 246 edges, 140 labeled nodes\n",
      "Epoch: 12, Loss: 1.7615, Train: 52.14%, Valid: 24.80% Test: 26.10%\n",
      "Sampled 432 nodes, 254 edges, 140 labeled nodes\n",
      "Epoch: 13, Loss: 1.7908, Train: 52.14%, Valid: 24.80% Test: 26.30%\n",
      "Sampled 394 nodes, 193 edges, 140 labeled nodes\n",
      "Epoch: 14, Loss: 1.7315, Train: 54.29%, Valid: 25.00% Test: 26.80%\n",
      "Sampled 423 nodes, 232 edges, 140 labeled nodes\n",
      "Epoch: 15, Loss: 1.6779, Train: 55.00%, Valid: 24.00% Test: 26.50%\n",
      "Sampled 355 nodes, 161 edges, 140 labeled nodes\n",
      "Epoch: 16, Loss: 1.7339, Train: 57.14%, Valid: 25.40% Test: 27.10%\n",
      "Sampled 439 nodes, 261 edges, 140 labeled nodes\n",
      "Epoch: 17, Loss: 1.6159, Train: 57.86%, Valid: 26.00% Test: 28.20%\n",
      "Sampled 392 nodes, 212 edges, 140 labeled nodes\n",
      "Epoch: 18, Loss: 1.6154, Train: 60.00%, Valid: 27.60% Test: 29.10%\n",
      "Sampled 389 nodes, 202 edges, 140 labeled nodes\n",
      "Epoch: 19, Loss: 1.6201, Train: 60.71%, Valid: 28.40% Test: 29.90%\n",
      "Sampled 355 nodes, 158 edges, 140 labeled nodes\n",
      "Epoch: 20, Loss: 1.7648, Train: 62.86%, Valid: 29.20% Test: 31.00%\n",
      "Sampled 430 nodes, 240 edges, 140 labeled nodes\n",
      "Epoch: 21, Loss: 1.5959, Train: 62.86%, Valid: 30.00% Test: 31.30%\n",
      "Sampled 433 nodes, 247 edges, 140 labeled nodes\n",
      "Epoch: 22, Loss: 1.6166, Train: 63.57%, Valid: 30.80% Test: 32.30%\n",
      "Sampled 429 nodes, 246 edges, 140 labeled nodes\n",
      "Epoch: 23, Loss: 1.5484, Train: 66.43%, Valid: 30.40% Test: 32.70%\n",
      "Sampled 378 nodes, 188 edges, 140 labeled nodes\n",
      "Epoch: 24, Loss: 1.5292, Train: 66.43%, Valid: 30.00% Test: 32.60%\n",
      "Sampled 460 nodes, 275 edges, 140 labeled nodes\n",
      "Epoch: 25, Loss: 1.6386, Train: 65.71%, Valid: 30.40% Test: 33.10%\n",
      "Sampled 379 nodes, 191 edges, 140 labeled nodes\n",
      "Epoch: 26, Loss: 1.5636, Train: 65.00%, Valid: 31.00% Test: 33.70%\n",
      "Sampled 447 nodes, 260 edges, 140 labeled nodes\n",
      "Epoch: 27, Loss: 1.6282, Train: 66.43%, Valid: 30.80% Test: 34.50%\n",
      "Sampled 407 nodes, 218 edges, 140 labeled nodes\n",
      "Epoch: 28, Loss: 1.7284, Train: 66.43%, Valid: 31.40% Test: 34.70%\n",
      "Sampled 461 nodes, 271 edges, 140 labeled nodes\n",
      "Epoch: 29, Loss: 1.6215, Train: 65.71%, Valid: 31.40% Test: 34.90%\n",
      "Sampled 367 nodes, 196 edges, 140 labeled nodes\n",
      "Epoch: 30, Loss: 1.4478, Train: 65.00%, Valid: 31.20% Test: 34.60%\n",
      "Sampled 385 nodes, 189 edges, 140 labeled nodes\n",
      "Epoch: 31, Loss: 1.4782, Train: 64.29%, Valid: 31.20% Test: 34.20%\n",
      "Sampled 457 nodes, 278 edges, 140 labeled nodes\n",
      "Epoch: 32, Loss: 1.5974, Train: 62.86%, Valid: 31.20% Test: 34.00%\n",
      "Sampled 434 nodes, 236 edges, 140 labeled nodes\n",
      "Epoch: 33, Loss: 1.6144, Train: 62.14%, Valid: 32.60% Test: 34.20%\n",
      "Sampled 374 nodes, 183 edges, 140 labeled nodes\n",
      "Epoch: 34, Loss: 1.6490, Train: 62.86%, Valid: 31.80% Test: 34.10%\n",
      "Sampled 375 nodes, 192 edges, 140 labeled nodes\n",
      "Epoch: 35, Loss: 1.4810, Train: 62.86%, Valid: 31.00% Test: 34.30%\n",
      "Sampled 424 nodes, 253 edges, 140 labeled nodes\n",
      "Epoch: 36, Loss: 1.5198, Train: 63.57%, Valid: 32.00% Test: 35.20%\n",
      "Sampled 448 nodes, 277 edges, 140 labeled nodes\n",
      "Epoch: 37, Loss: 1.5755, Train: 64.29%, Valid: 31.80% Test: 34.90%\n",
      "Sampled 433 nodes, 231 edges, 140 labeled nodes\n",
      "Epoch: 38, Loss: 1.5269, Train: 62.14%, Valid: 31.60% Test: 34.80%\n",
      "Sampled 371 nodes, 186 edges, 140 labeled nodes\n",
      "Epoch: 39, Loss: 1.5464, Train: 62.86%, Valid: 31.80% Test: 35.40%\n",
      "Sampled 400 nodes, 201 edges, 140 labeled nodes\n",
      "Epoch: 40, Loss: 1.6209, Train: 62.14%, Valid: 32.60% Test: 35.30%\n",
      "Sampled 421 nodes, 243 edges, 140 labeled nodes\n",
      "Epoch: 41, Loss: 1.4806, Train: 63.57%, Valid: 33.20% Test: 35.70%\n",
      "Sampled 457 nodes, 256 edges, 140 labeled nodes\n",
      "Epoch: 42, Loss: 1.5353, Train: 64.29%, Valid: 34.40% Test: 34.40%\n",
      "Sampled 406 nodes, 223 edges, 140 labeled nodes\n",
      "Epoch: 43, Loss: 1.5749, Train: 64.29%, Valid: 34.40% Test: 34.90%\n",
      "Sampled 449 nodes, 258 edges, 140 labeled nodes\n",
      "Epoch: 44, Loss: 1.6295, Train: 62.14%, Valid: 34.40% Test: 36.20%\n",
      "Sampled 414 nodes, 235 edges, 140 labeled nodes\n",
      "Epoch: 45, Loss: 1.5811, Train: 62.86%, Valid: 34.40% Test: 36.20%\n",
      "Sampled 408 nodes, 216 edges, 140 labeled nodes\n",
      "Epoch: 46, Loss: 1.4394, Train: 62.14%, Valid: 34.40% Test: 36.10%\n",
      "Sampled 403 nodes, 205 edges, 140 labeled nodes\n",
      "Epoch: 47, Loss: 1.5136, Train: 61.43%, Valid: 33.40% Test: 35.60%\n",
      "Sampled 406 nodes, 218 edges, 140 labeled nodes\n",
      "Epoch: 48, Loss: 1.4539, Train: 60.71%, Valid: 33.60% Test: 35.40%\n",
      "Sampled 403 nodes, 218 edges, 140 labeled nodes\n",
      "Epoch: 49, Loss: 1.5832, Train: 62.86%, Valid: 33.60% Test: 35.60%\n",
      "Sampled 389 nodes, 191 edges, 140 labeled nodes\n",
      "Epoch: 50, Loss: 1.5550, Train: 62.86%, Valid: 33.80% Test: 36.50%\n",
      "Best model: Train: 64.29%, Valid: 34.40% Test: 34.40%\n"
     ]
    }
   ],
   "source": [
    "# Change the ratio to 0.3\n",
    "args['ratios'] = (0.3, 0.3, 1)\n",
    "\n",
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "\n",
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "graphs = [graph_train, graph_val, graph_test]\n",
    "batch_best_model, batch_accs_1 = train(graphs, graphs, args, model, optimizer)\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], batch_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "EePAvNlGUM2K"
   },
   "source": [
    "## Visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "id": "7etNAkXAT55d"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 648x504 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "batch_results = np.array(batch_accs)\n",
    "batch_results_1 = np.array(batch_accs_1)\n",
    "all_results = np.array(all_accs)\n",
    "\n",
    "x = np.arange(1, 51)\n",
    "\n",
    "plt.figure(figsize=(9, 7))\n",
    "\n",
    "plt.plot(x, batch_results[:, 0], label=\"Batch 0.8 Train\")\n",
    "plt.plot(x, batch_results[:, 1], label=\"Batch 0.8 Validation\")\n",
    "plt.plot(x, batch_results[:, 2], label=\"Batch 0.8 Test\")\n",
    "plt.plot(x, batch_results_1[:, 0], label=\"Batch 0.3 Train\")\n",
    "plt.plot(x, batch_results_1[:, 1], label=\"Batch 0.3 Validation\")\n",
    "plt.plot(x, batch_results_1[:, 2], label=\"Batch 0.3 Test\")\n",
    "plt.plot(x, all_results[:, 0], label=\"All Train\")\n",
    "plt.plot(x, all_results[:, 1], label=\"All Validation\")\n",
    "plt.plot(x, all_results[:, 2], label=\"All Test\")\n",
    "plt.title('Model Accuracy')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bkA7-0groq7q"
   },
   "source": [
    "Here all accuracies are evaluated on the full-batch mode."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Iee0U8KGURc8"
   },
   "source": [
    "# 3 Cluster Sampling\n",
    "\n",
    "Instead of the neighbor sampling, we can use another approach, subgraph (cluster) sampling, to scale up GNN. This approach is proposed in Cluster-GCN ([Chiang et al. (2019)](https://arxiv.org/abs/1905.07953)).\n",
    "\n",
    "In this section, we will implement vanilla Cluster-GCN and experiment with 3 different community partition algorithms.\n",
    "\n",
    "Notice that this section requires you have run the `Setup`, `GNN Model` and `Training and Testing` cells of the last section."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_BXjP79gUYir"
   },
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "id": "UGQ_VKp8UOEm"
   },
   "outputs": [],
   "source": [
    "import copy\n",
    "import torch\n",
    "import random\n",
    "import numpy as np\n",
    "import networkx as nx\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import community as community_louvain\n",
    "\n",
    "from torch_geometric.nn import SAGEConv\n",
    "from torch.utils.data import DataLoader\n",
    "from torch_geometric.datasets import Planetoid\n",
    "from torch.nn import Sequential, Linear, ReLU\n",
    "from deepsnap.dataset import GraphDataset\n",
    "from deepsnap.graph import Graph\n",
    "\n",
    "pyg_dataset = Planetoid('./tmp/cora', \"Cora\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "id": "bzMatyCSUaB6"
   },
   "outputs": [],
   "source": [
    "args = {\n",
    "    'device': torch.device('cuda' if torch.cuda.is_available() else 'cpu'),\n",
    "    'dropout': 0.5,\n",
    "    'num_layers': 2,\n",
    "    'hidden_size': 64,\n",
    "    'lr': 0.005,\n",
    "    'epochs': 150,\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ekV-sokSUeLc"
   },
   "source": [
    "## Partition the Graph into Clusters\n",
    "\n",
    "Here we use following three community detection / partition algorithms to partition the graph into different clusters:\n",
    "* [Kernighan–Lin algorithm (bisection)](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.community.kernighan_lin.kernighan_lin_bisection.html)\n",
    "* [Clauset-Newman-Moore greedy modularity maximization](https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.community.modularity_max.greedy_modularity_communities.html#networkx.algorithms.community.modularity_max.greedy_modularity_communities)\n",
    "* [Louvain algorithm](https://python-louvain.readthedocs.io/en/latest/api.html)\n",
    "\n",
    "\n",
    "To make the training more stable, we discard the cluster that has less than 10 nodes.\n",
    "\n",
    "Let's first define these algorithms as DeepSNAP transformation on a graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "id": "N8XeT005UcKh"
   },
   "outputs": [],
   "source": [
    "def preprocess(G, node_label_index, method=\"louvain\"):\n",
    "    graphs = []\n",
    "    labeled_nodes = set(node_label_index.tolist())\n",
    "    if method == \"louvain\":\n",
    "        community_mapping = community_louvain.best_partition(G, resolution=10)\n",
    "        communities = {}\n",
    "        for node in community_mapping:\n",
    "            comm = community_mapping[node]\n",
    "            if comm in communities:\n",
    "                communities[comm].add(node)\n",
    "            else:\n",
    "                communities[comm] = set([node])\n",
    "        communities = communities.values()\n",
    "    elif method == \"bisection\":\n",
    "        communities = nx.algorithms.community.kernighan_lin_bisection(G)\n",
    "    elif method == \"greedy\":\n",
    "        communities = nx.algorithms.community.greedy_modularity_communities(G)\n",
    "\n",
    "    for community in communities:\n",
    "        nodes = set(community)\n",
    "        subgraph = G.subgraph(nodes)\n",
    "        # Make sure each subgraph has more than 10 nodes\n",
    "        if subgraph.number_of_nodes() > 10:\n",
    "            node_mapping = {node : i for i, node in enumerate(subgraph.nodes())}\n",
    "            subgraph = nx.relabel_nodes(subgraph, node_mapping)\n",
    "            # Get the id of the training set labeled node in the new graph\n",
    "            train_label_index = []\n",
    "            for node in labeled_nodes:\n",
    "                if node in node_mapping:\n",
    "                    # Append relabeled labeled node index\n",
    "                    train_label_index.append(node_mapping[node])\n",
    "\n",
    "            # Make sure the subgraph contains at least one training set labeled node\n",
    "            if len(train_label_index) > 0:\n",
    "                dg = Graph(subgraph)\n",
    "                # Update node_label_index\n",
    "                dg.node_label_index = torch.tensor(train_label_index, dtype=torch.long)\n",
    "                graphs.append(dg)\n",
    "    return graphs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7CYEamCAU-TJ"
   },
   "source": [
    "## Louvain Preprocess"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "-TrC6ybWU7eO"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Partition the graph in to 5 communities\n",
      "Each community has 502 nodes in average\n",
      "Each community has 980 edges in average\n"
     ]
    }
   ],
   "source": [
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "graphs = preprocess(graph_train.G, graph_train.node_label_index, method=\"louvain\")\n",
    "print(\"Partition the graph in to {} communities\".format(len(graphs)))\n",
    "avg_num_nodes = 0\n",
    "avg_num_edges = 0\n",
    "for graph in graphs:\n",
    "    avg_num_nodes += graph.num_nodes\n",
    "    avg_num_edges += graph.num_edges\n",
    "avg_num_nodes = int(avg_num_nodes / len(graphs))\n",
    "avg_num_edges = int(avg_num_edges / len(graphs))\n",
    "print(\"Each community has {} nodes in average\".format(avg_num_nodes))\n",
    "print(\"Each community has {} edges in average\".format(avg_num_edges))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "O03uXIuGVIgJ"
   },
   "source": [
    "## Louvain Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "id": "iSbGf5ADVFQq"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 01, Loss: 1.8291, Train: 20.71%, Valid: 8.20% Test: 9.40%\n",
      "Epoch: 02, Loss: 2.2946, Train: 15.00%, Valid: 5.20% Test: 6.00%\n",
      "Epoch: 03, Loss: 0.8497, Train: 17.86%, Valid: 4.60% Test: 6.10%\n",
      "Epoch: 04, Loss: 2.2201, Train: 18.57%, Valid: 5.00% Test: 6.00%\n",
      "Epoch: 05, Loss: 3.4288, Train: 18.57%, Valid: 5.00% Test: 6.40%\n",
      "Epoch: 06, Loss: 0.0475, Train: 19.29%, Valid: 5.60% Test: 7.20%\n",
      "Epoch: 07, Loss: 0.0318, Train: 17.14%, Valid: 6.80% Test: 8.50%\n",
      "Epoch: 08, Loss: 0.0159, Train: 18.57%, Valid: 8.40% Test: 10.60%\n",
      "Epoch: 09, Loss: 0.9078, Train: 19.29%, Valid: 7.20% Test: 9.20%\n",
      "Epoch: 10, Loss: 3.0201, Train: 18.57%, Valid: 6.80% Test: 8.60%\n",
      "Epoch: 11, Loss: 0.0043, Train: 20.00%, Valid: 7.40% Test: 9.30%\n",
      "Epoch: 12, Loss: 0.0188, Train: 20.71%, Valid: 7.00% Test: 10.00%\n",
      "Epoch: 13, Loss: 1.3147, Train: 27.14%, Valid: 7.20% Test: 9.40%\n",
      "Epoch: 14, Loss: 1.1787, Train: 40.00%, Valid: 7.60% Test: 10.10%\n",
      "Epoch: 15, Loss: 1.7444, Train: 45.71%, Valid: 9.60% Test: 12.00%\n",
      "Epoch: 16, Loss: 0.2668, Train: 46.43%, Valid: 9.00% Test: 10.10%\n",
      "Epoch: 17, Loss: 0.0639, Train: 54.29%, Valid: 12.40% Test: 12.10%\n",
      "Epoch: 18, Loss: 0.5833, Train: 60.00%, Valid: 13.80% Test: 14.30%\n",
      "Epoch: 19, Loss: 0.4809, Train: 67.86%, Valid: 17.80% Test: 16.60%\n",
      "Epoch: 20, Loss: 0.3727, Train: 70.71%, Valid: 20.00% Test: 19.60%\n",
      "Epoch: 21, Loss: 1.2101, Train: 77.14%, Valid: 22.40% Test: 22.50%\n",
      "Epoch: 22, Loss: 0.0284, Train: 72.86%, Valid: 19.40% Test: 20.00%\n",
      "Epoch: 23, Loss: 0.0083, Train: 70.71%, Valid: 17.00% Test: 17.40%\n",
      "Epoch: 24, Loss: 0.0380, Train: 68.57%, Valid: 15.20% Test: 16.10%\n",
      "Epoch: 25, Loss: 0.1763, Train: 73.57%, Valid: 17.20% Test: 18.20%\n",
      "Epoch: 26, Loss: 0.8878, Train: 77.86%, Valid: 19.80% Test: 21.30%\n",
      "Epoch: 27, Loss: 0.0468, Train: 85.71%, Valid: 24.60% Test: 25.30%\n",
      "Epoch: 28, Loss: 0.0504, Train: 89.29%, Valid: 29.20% Test: 30.40%\n",
      "Epoch: 29, Loss: 0.0976, Train: 92.14%, Valid: 32.00% Test: 33.40%\n",
      "Epoch: 30, Loss: 0.6042, Train: 92.86%, Valid: 35.40% Test: 37.40%\n",
      "Epoch: 31, Loss: 0.0287, Train: 92.86%, Valid: 30.60% Test: 32.10%\n",
      "Epoch: 32, Loss: 0.2958, Train: 93.57%, Valid: 33.60% Test: 36.10%\n",
      "Epoch: 33, Loss: 0.0083, Train: 93.57%, Valid: 28.60% Test: 30.80%\n",
      "Epoch: 34, Loss: 0.0208, Train: 92.14%, Valid: 32.40% Test: 33.70%\n",
      "Epoch: 35, Loss: 0.0072, Train: 92.14%, Valid: 36.60% Test: 37.00%\n",
      "Epoch: 36, Loss: 0.0079, Train: 92.14%, Valid: 32.80% Test: 32.50%\n",
      "Epoch: 37, Loss: 0.0010, Train: 92.14%, Valid: 34.60% Test: 36.90%\n",
      "Epoch: 38, Loss: 0.2558, Train: 92.14%, Valid: 38.00% Test: 39.00%\n",
      "Epoch: 39, Loss: 0.1789, Train: 92.14%, Valid: 39.00% Test: 41.30%\n",
      "Epoch: 40, Loss: 0.1946, Train: 92.14%, Valid: 42.00% Test: 42.20%\n",
      "Epoch: 41, Loss: 0.0168, Train: 91.43%, Valid: 43.40% Test: 44.20%\n",
      "Epoch: 42, Loss: 0.1341, Train: 92.14%, Valid: 44.20% Test: 44.80%\n",
      "Epoch: 43, Loss: 0.0004, Train: 91.43%, Valid: 46.60% Test: 46.00%\n",
      "Epoch: 44, Loss: 0.0962, Train: 91.43%, Valid: 46.40% Test: 46.60%\n",
      "Epoch: 45, Loss: 0.0929, Train: 91.43%, Valid: 46.80% Test: 47.40%\n",
      "Epoch: 46, Loss: 0.0018, Train: 91.43%, Valid: 47.00% Test: 48.20%\n",
      "Epoch: 47, Loss: 0.0467, Train: 90.71%, Valid: 47.00% Test: 48.60%\n",
      "Epoch: 48, Loss: 0.0026, Train: 90.71%, Valid: 46.80% Test: 47.80%\n",
      "Epoch: 49, Loss: 0.0009, Train: 90.71%, Valid: 46.00% Test: 46.30%\n",
      "Epoch: 50, Loss: 0.0255, Train: 90.71%, Valid: 46.80% Test: 47.40%\n",
      "Epoch: 51, Loss: 0.0007, Train: 90.71%, Valid: 44.80% Test: 46.30%\n",
      "Epoch: 52, Loss: 0.0034, Train: 91.43%, Valid: 43.20% Test: 44.20%\n",
      "Epoch: 53, Loss: 0.0008, Train: 91.43%, Valid: 44.20% Test: 44.80%\n",
      "Epoch: 54, Loss: 0.0003, Train: 91.43%, Valid: 43.40% Test: 44.20%\n",
      "Epoch: 55, Loss: 0.0182, Train: 90.71%, Valid: 44.00% Test: 44.80%\n",
      "Epoch: 56, Loss: 0.0743, Train: 91.43%, Valid: 44.60% Test: 45.50%\n",
      "Epoch: 57, Loss: 0.0011, Train: 91.43%, Valid: 43.20% Test: 44.10%\n",
      "Epoch: 58, Loss: 0.0014, Train: 90.71%, Valid: 44.80% Test: 45.80%\n",
      "Epoch: 59, Loss: 0.0089, Train: 90.71%, Valid: 45.20% Test: 46.80%\n",
      "Epoch: 60, Loss: 0.0008, Train: 90.71%, Valid: 44.80% Test: 46.10%\n",
      "Epoch: 61, Loss: 0.0371, Train: 91.43%, Valid: 45.40% Test: 46.70%\n",
      "Epoch: 62, Loss: 0.0142, Train: 91.43%, Valid: 45.40% Test: 47.60%\n",
      "Epoch: 63, Loss: 0.0102, Train: 91.43%, Valid: 45.80% Test: 48.40%\n",
      "Epoch: 64, Loss: 0.0437, Train: 91.43%, Valid: 46.80% Test: 48.80%\n",
      "Epoch: 65, Loss: 0.0507, Train: 91.43%, Valid: 47.80% Test: 49.10%\n",
      "Epoch: 66, Loss: 0.0010, Train: 91.43%, Valid: 46.40% Test: 48.80%\n",
      "Epoch: 67, Loss: 0.0053, Train: 91.43%, Valid: 46.20% Test: 46.50%\n",
      "Epoch: 68, Loss: 0.0166, Train: 91.43%, Valid: 46.40% Test: 47.10%\n",
      "Epoch: 69, Loss: 0.0000, Train: 91.43%, Valid: 47.00% Test: 47.90%\n",
      "Epoch: 70, Loss: 0.0000, Train: 91.43%, Valid: 46.60% Test: 48.90%\n",
      "Epoch: 71, Loss: 0.0125, Train: 91.43%, Valid: 47.20% Test: 48.90%\n",
      "Epoch: 72, Loss: 0.0077, Train: 91.43%, Valid: 47.60% Test: 49.30%\n",
      "Epoch: 73, Loss: 0.0138, Train: 91.43%, Valid: 48.80% Test: 49.40%\n",
      "Epoch: 74, Loss: 0.0149, Train: 91.43%, Valid: 48.60% Test: 49.80%\n",
      "Epoch: 75, Loss: 0.0064, Train: 92.14%, Valid: 46.20% Test: 47.50%\n",
      "Epoch: 76, Loss: 0.1604, Train: 92.14%, Valid: 46.40% Test: 48.20%\n",
      "Epoch: 77, Loss: 0.0004, Train: 92.14%, Valid: 46.00% Test: 47.70%\n",
      "Epoch: 78, Loss: 0.0017, Train: 92.14%, Valid: 43.40% Test: 45.20%\n",
      "Epoch: 79, Loss: 0.0059, Train: 92.14%, Valid: 44.60% Test: 45.60%\n",
      "Epoch: 80, Loss: 0.0001, Train: 92.14%, Valid: 44.60% Test: 45.80%\n",
      "Epoch: 81, Loss: 0.0113, Train: 92.14%, Valid: 45.40% Test: 45.90%\n",
      "Epoch: 82, Loss: 0.0139, Train: 92.14%, Valid: 45.60% Test: 46.30%\n",
      "Epoch: 83, Loss: 0.0002, Train: 92.14%, Valid: 46.40% Test: 47.70%\n",
      "Epoch: 84, Loss: 0.0007, Train: 92.14%, Valid: 44.00% Test: 45.90%\n",
      "Epoch: 85, Loss: 0.0063, Train: 92.14%, Valid: 45.20% Test: 46.00%\n",
      "Epoch: 86, Loss: 0.0124, Train: 92.14%, Valid: 45.40% Test: 46.40%\n",
      "Epoch: 87, Loss: 0.0024, Train: 92.14%, Valid: 45.20% Test: 46.30%\n",
      "Epoch: 88, Loss: 0.0103, Train: 92.14%, Valid: 45.40% Test: 46.30%\n",
      "Epoch: 89, Loss: 0.0014, Train: 92.14%, Valid: 45.80% Test: 47.10%\n",
      "Epoch: 90, Loss: 0.0061, Train: 92.14%, Valid: 46.60% Test: 47.50%\n",
      "Epoch: 91, Loss: 0.0086, Train: 92.14%, Valid: 47.00% Test: 48.30%\n",
      "Epoch: 92, Loss: 0.0122, Train: 92.14%, Valid: 47.20% Test: 48.20%\n",
      "Epoch: 93, Loss: 0.0000, Train: 92.14%, Valid: 49.00% Test: 49.80%\n",
      "Epoch: 94, Loss: 0.0044, Train: 92.14%, Valid: 49.40% Test: 50.00%\n",
      "Epoch: 95, Loss: 0.0019, Train: 92.14%, Valid: 46.00% Test: 47.70%\n",
      "Epoch: 96, Loss: 0.0043, Train: 92.14%, Valid: 46.80% Test: 48.30%\n",
      "Epoch: 97, Loss: 0.0021, Train: 92.14%, Valid: 46.80% Test: 48.10%\n",
      "Epoch: 98, Loss: 0.0000, Train: 92.14%, Valid: 49.20% Test: 48.20%\n",
      "Epoch: 99, Loss: 0.0025, Train: 92.14%, Valid: 49.20% Test: 49.20%\n",
      "Epoch: 100, Loss: 0.0005, Train: 92.14%, Valid: 46.80% Test: 47.40%\n",
      "Epoch: 101, Loss: 0.0163, Train: 92.14%, Valid: 46.80% Test: 47.80%\n",
      "Epoch: 102, Loss: 0.0106, Train: 92.14%, Valid: 46.80% Test: 48.30%\n",
      "Epoch: 103, Loss: 0.0012, Train: 92.86%, Valid: 43.80% Test: 45.70%\n",
      "Epoch: 104, Loss: 0.0003, Train: 92.14%, Valid: 44.40% Test: 45.90%\n",
      "Epoch: 105, Loss: 0.0050, Train: 92.14%, Valid: 45.40% Test: 46.60%\n",
      "Epoch: 106, Loss: 0.0028, Train: 92.14%, Valid: 45.60% Test: 47.40%\n",
      "Epoch: 107, Loss: 0.0002, Train: 92.14%, Valid: 48.00% Test: 48.20%\n",
      "Epoch: 108, Loss: 0.0011, Train: 92.14%, Valid: 45.00% Test: 46.00%\n",
      "Epoch: 109, Loss: 0.0028, Train: 92.14%, Valid: 45.20% Test: 46.50%\n",
      "Epoch: 110, Loss: 0.0054, Train: 92.14%, Valid: 45.80% Test: 47.30%\n",
      "Epoch: 111, Loss: 0.0014, Train: 92.86%, Valid: 42.20% Test: 44.60%\n",
      "Epoch: 112, Loss: 0.0000, Train: 92.14%, Valid: 45.00% Test: 46.50%\n",
      "Epoch: 113, Loss: 0.0088, Train: 92.14%, Valid: 45.20% Test: 47.30%\n",
      "Epoch: 114, Loss: 0.0058, Train: 92.14%, Valid: 45.80% Test: 47.00%\n",
      "Epoch: 115, Loss: 0.0000, Train: 92.14%, Valid: 47.80% Test: 48.90%\n",
      "Epoch: 116, Loss: 0.0071, Train: 92.14%, Valid: 44.20% Test: 45.90%\n",
      "Epoch: 117, Loss: 0.0095, Train: 92.14%, Valid: 45.20% Test: 47.00%\n",
      "Epoch: 118, Loss: 0.0004, Train: 92.86%, Valid: 42.20% Test: 44.60%\n",
      "Epoch: 119, Loss: 0.0023, Train: 92.86%, Valid: 42.60% Test: 45.50%\n",
      "Epoch: 120, Loss: 0.0002, Train: 92.14%, Valid: 42.80% Test: 45.90%\n",
      "Epoch: 121, Loss: 0.0077, Train: 92.86%, Valid: 40.00% Test: 43.30%\n",
      "Epoch: 122, Loss: 0.0004, Train: 92.86%, Valid: 42.80% Test: 45.70%\n",
      "Epoch: 123, Loss: 0.0021, Train: 92.86%, Valid: 43.80% Test: 46.00%\n",
      "Epoch: 124, Loss: 0.0000, Train: 92.14%, Valid: 45.20% Test: 47.80%\n",
      "Epoch: 125, Loss: 0.0003, Train: 92.14%, Valid: 45.60% Test: 46.90%\n",
      "Epoch: 126, Loss: 0.0023, Train: 92.14%, Valid: 46.40% Test: 47.10%\n",
      "Epoch: 127, Loss: 0.0161, Train: 92.14%, Valid: 46.00% Test: 47.40%\n",
      "Epoch: 128, Loss: 0.0000, Train: 92.14%, Valid: 47.80% Test: 48.50%\n",
      "Epoch: 129, Loss: 0.0016, Train: 92.14%, Valid: 47.40% Test: 48.20%\n",
      "Epoch: 130, Loss: 0.0022, Train: 92.14%, Valid: 47.60% Test: 48.20%\n",
      "Epoch: 131, Loss: 0.0059, Train: 92.14%, Valid: 49.80% Test: 50.90%\n",
      "Epoch: 132, Loss: 0.0001, Train: 92.14%, Valid: 49.40% Test: 49.60%\n",
      "Epoch: 133, Loss: 0.0045, Train: 92.14%, Valid: 49.80% Test: 49.90%\n",
      "Epoch: 134, Loss: 0.0002, Train: 92.14%, Valid: 49.60% Test: 51.40%\n",
      "Epoch: 135, Loss: 0.0000, Train: 92.14%, Valid: 51.20% Test: 51.60%\n",
      "Epoch: 136, Loss: 0.0001, Train: 92.14%, Valid: 47.80% Test: 49.60%\n",
      "Epoch: 137, Loss: 0.0002, Train: 91.43%, Valid: 49.60% Test: 51.70%\n",
      "Epoch: 138, Loss: 0.0003, Train: 91.43%, Valid: 45.40% Test: 47.60%\n",
      "Epoch: 139, Loss: 0.0001, Train: 92.14%, Valid: 41.80% Test: 45.20%\n",
      "Epoch: 140, Loss: 0.0006, Train: 92.86%, Valid: 41.80% Test: 45.40%\n",
      "Epoch: 141, Loss: 0.0013, Train: 92.14%, Valid: 42.80% Test: 45.80%\n",
      "Epoch: 142, Loss: 0.0001, Train: 92.14%, Valid: 43.80% Test: 45.80%\n",
      "Epoch: 143, Loss: 0.0013, Train: 92.14%, Valid: 44.60% Test: 46.30%\n",
      "Epoch: 144, Loss: 0.0004, Train: 93.57%, Valid: 41.20% Test: 43.50%\n",
      "Epoch: 145, Loss: 0.0001, Train: 92.86%, Valid: 41.40% Test: 44.20%\n",
      "Epoch: 146, Loss: 0.0008, Train: 93.57%, Valid: 38.80% Test: 41.10%\n",
      "Epoch: 147, Loss: 0.0012, Train: 93.57%, Valid: 36.20% Test: 37.20%\n",
      "Epoch: 148, Loss: 0.0006, Train: 93.57%, Valid: 37.80% Test: 39.00%\n",
      "Epoch: 149, Loss: 0.0000, Train: 93.57%, Valid: 37.40% Test: 40.80%\n",
      "Epoch: 150, Loss: 0.0000, Train: 93.57%, Valid: 36.00% Test: 36.70%\n",
      "Best model: Train: 92.14%, Valid: 51.20% Test: 51.60%\n"
     ]
    }
   ],
   "source": [
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "louvain_best_model, louvain_accs = train(graphs, [graph_train, graph_val, graph_test], args, model, optimizer, mode=\"community\")\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], louvain_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6CvTf0ANVO9U"
   },
   "source": [
    "## Bisection Preprocess"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "id": "HkV0zlhgVJ7u"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Partition the graph in to 2 communities\n",
      "Each community has 1354 nodes in average\n",
      "Each community has 1385 edges in average\n"
     ]
    }
   ],
   "source": [
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "graphs = preprocess(graph_train.G, graph_train.node_label_index, method=\"bisection\")\n",
    "print(\"Partition the graph in to {} communities\".format(len(graphs)))\n",
    "avg_num_nodes = 0\n",
    "avg_num_edges = 0\n",
    "for graph in graphs:\n",
    "    avg_num_nodes += graph.num_nodes\n",
    "    avg_num_edges += graph.num_edges\n",
    "avg_num_nodes = int(avg_num_nodes / len(graphs))\n",
    "avg_num_edges = int(avg_num_edges / len(graphs))\n",
    "print(\"Each community has {} nodes in average\".format(avg_num_nodes))\n",
    "print(\"Each community has {} edges in average\".format(avg_num_edges))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IqMCvP8wVVms"
   },
   "source": [
    "## Bisection Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "id": "k1wgFg1bVRGY"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 01, Loss: 1.9783, Train: 14.29%, Valid: 12.20% Test: 13.00%\n",
      "Epoch: 02, Loss: 1.1818, Train: 23.57%, Valid: 13.40% Test: 14.70%\n",
      "Epoch: 03, Loss: 0.6185, Train: 40.71%, Valid: 20.00% Test: 20.30%\n",
      "Epoch: 04, Loss: 1.7542, Train: 57.14%, Valid: 31.20% Test: 32.10%\n",
      "Epoch: 05, Loss: 0.2475, Train: 72.86%, Valid: 41.40% Test: 44.20%\n",
      "Epoch: 06, Loss: 0.8587, Train: 90.00%, Valid: 54.20% Test: 55.00%\n",
      "Epoch: 07, Loss: 0.5534, Train: 95.71%, Valid: 61.00% Test: 62.30%\n",
      "Epoch: 08, Loss: 0.2826, Train: 97.86%, Valid: 64.40% Test: 67.00%\n",
      "Epoch: 09, Loss: 0.1850, Train: 99.29%, Valid: 66.60% Test: 67.40%\n",
      "Epoch: 10, Loss: 0.1331, Train: 99.29%, Valid: 65.80% Test: 66.40%\n",
      "Epoch: 11, Loss: 0.0945, Train: 99.29%, Valid: 64.20% Test: 64.40%\n",
      "Epoch: 12, Loss: 0.0548, Train: 99.29%, Valid: 64.20% Test: 63.70%\n",
      "Epoch: 13, Loss: 0.2023, Train: 99.29%, Valid: 64.60% Test: 64.00%\n",
      "Epoch: 14, Loss: 0.1327, Train: 99.29%, Valid: 65.80% Test: 65.30%\n",
      "Epoch: 15, Loss: 0.0523, Train: 99.29%, Valid: 66.20% Test: 66.30%\n",
      "Epoch: 16, Loss: 0.0733, Train: 99.29%, Valid: 66.20% Test: 66.50%\n",
      "Epoch: 17, Loss: 0.0507, Train: 99.29%, Valid: 67.00% Test: 67.70%\n",
      "Epoch: 18, Loss: 0.0546, Train: 99.29%, Valid: 67.40% Test: 67.90%\n",
      "Epoch: 19, Loss: 0.0135, Train: 99.29%, Valid: 67.40% Test: 68.00%\n",
      "Epoch: 20, Loss: 0.0491, Train: 99.29%, Valid: 67.40% Test: 68.50%\n",
      "Epoch: 21, Loss: 0.0037, Train: 99.29%, Valid: 67.80% Test: 68.60%\n",
      "Epoch: 22, Loss: 0.0127, Train: 100.00%, Valid: 67.80% Test: 68.70%\n",
      "Epoch: 23, Loss: 0.0034, Train: 100.00%, Valid: 67.80% Test: 68.60%\n",
      "Epoch: 24, Loss: 0.0026, Train: 100.00%, Valid: 68.00% Test: 68.40%\n",
      "Epoch: 25, Loss: 0.0089, Train: 100.00%, Valid: 67.80% Test: 68.40%\n",
      "Epoch: 26, Loss: 0.0158, Train: 100.00%, Valid: 67.60% Test: 68.10%\n",
      "Epoch: 27, Loss: 0.0112, Train: 100.00%, Valid: 67.60% Test: 67.80%\n",
      "Epoch: 28, Loss: 0.0045, Train: 100.00%, Valid: 67.80% Test: 68.00%\n",
      "Epoch: 29, Loss: 0.0319, Train: 100.00%, Valid: 68.20% Test: 68.50%\n",
      "Epoch: 30, Loss: 0.0050, Train: 100.00%, Valid: 68.20% Test: 68.20%\n",
      "Epoch: 31, Loss: 0.0047, Train: 100.00%, Valid: 68.40% Test: 68.20%\n",
      "Epoch: 32, Loss: 0.0312, Train: 100.00%, Valid: 68.40% Test: 68.20%\n",
      "Epoch: 33, Loss: 0.0201, Train: 100.00%, Valid: 68.60% Test: 68.20%\n",
      "Epoch: 34, Loss: 0.0187, Train: 100.00%, Valid: 68.40% Test: 68.10%\n",
      "Epoch: 35, Loss: 0.0096, Train: 100.00%, Valid: 68.40% Test: 68.30%\n",
      "Epoch: 36, Loss: 0.0095, Train: 100.00%, Valid: 68.40% Test: 68.30%\n",
      "Epoch: 37, Loss: 0.0073, Train: 100.00%, Valid: 68.60% Test: 68.20%\n",
      "Epoch: 38, Loss: 0.0022, Train: 100.00%, Valid: 68.40% Test: 68.40%\n",
      "Epoch: 39, Loss: 0.0083, Train: 100.00%, Valid: 68.40% Test: 68.20%\n",
      "Epoch: 40, Loss: 0.0063, Train: 100.00%, Valid: 68.20% Test: 67.80%\n",
      "Epoch: 41, Loss: 0.0009, Train: 100.00%, Valid: 68.60% Test: 67.90%\n",
      "Epoch: 42, Loss: 0.0049, Train: 100.00%, Valid: 68.80% Test: 68.00%\n",
      "Epoch: 43, Loss: 0.0009, Train: 100.00%, Valid: 68.80% Test: 68.00%\n",
      "Epoch: 44, Loss: 0.0007, Train: 100.00%, Valid: 68.40% Test: 67.70%\n",
      "Epoch: 45, Loss: 0.0163, Train: 100.00%, Valid: 68.40% Test: 67.80%\n",
      "Epoch: 46, Loss: 0.0020, Train: 100.00%, Valid: 68.20% Test: 67.60%\n",
      "Epoch: 47, Loss: 0.0048, Train: 100.00%, Valid: 68.20% Test: 67.70%\n",
      "Epoch: 48, Loss: 0.0005, Train: 100.00%, Valid: 68.20% Test: 67.40%\n",
      "Epoch: 49, Loss: 0.0007, Train: 100.00%, Valid: 67.80% Test: 67.60%\n",
      "Epoch: 50, Loss: 0.0006, Train: 100.00%, Valid: 67.80% Test: 67.60%\n",
      "Epoch: 51, Loss: 0.0023, Train: 100.00%, Valid: 67.60% Test: 67.60%\n",
      "Epoch: 52, Loss: 0.0048, Train: 100.00%, Valid: 67.60% Test: 67.70%\n",
      "Epoch: 53, Loss: 0.0019, Train: 100.00%, Valid: 67.40% Test: 67.90%\n",
      "Epoch: 54, Loss: 0.0009, Train: 100.00%, Valid: 67.60% Test: 67.80%\n",
      "Epoch: 55, Loss: 0.0033, Train: 100.00%, Valid: 67.60% Test: 67.80%\n",
      "Epoch: 56, Loss: 0.0009, Train: 100.00%, Valid: 68.00% Test: 67.80%\n",
      "Epoch: 57, Loss: 0.0060, Train: 100.00%, Valid: 68.20% Test: 68.10%\n",
      "Epoch: 58, Loss: 0.0019, Train: 100.00%, Valid: 68.00% Test: 67.80%\n",
      "Epoch: 59, Loss: 0.0008, Train: 100.00%, Valid: 67.40% Test: 67.90%\n",
      "Epoch: 60, Loss: 0.0038, Train: 100.00%, Valid: 67.80% Test: 67.80%\n",
      "Epoch: 61, Loss: 0.0005, Train: 100.00%, Valid: 67.40% Test: 67.90%\n",
      "Epoch: 62, Loss: 0.0123, Train: 100.00%, Valid: 67.80% Test: 67.80%\n",
      "Epoch: 63, Loss: 0.0029, Train: 100.00%, Valid: 68.20% Test: 67.80%\n",
      "Epoch: 64, Loss: 0.0213, Train: 100.00%, Valid: 68.20% Test: 68.00%\n",
      "Epoch: 65, Loss: 0.0026, Train: 100.00%, Valid: 67.80% Test: 67.80%\n",
      "Epoch: 66, Loss: 0.0002, Train: 100.00%, Valid: 67.40% Test: 67.60%\n",
      "Epoch: 67, Loss: 0.0003, Train: 100.00%, Valid: 67.80% Test: 67.70%\n",
      "Epoch: 68, Loss: 0.0001, Train: 100.00%, Valid: 67.80% Test: 67.60%\n",
      "Epoch: 69, Loss: 0.0001, Train: 100.00%, Valid: 68.20% Test: 67.80%\n",
      "Epoch: 70, Loss: 0.0004, Train: 100.00%, Valid: 68.40% Test: 67.90%\n",
      "Epoch: 71, Loss: 0.0007, Train: 100.00%, Valid: 68.40% Test: 67.80%\n",
      "Epoch: 72, Loss: 0.0007, Train: 100.00%, Valid: 67.80% Test: 67.70%\n",
      "Epoch: 73, Loss: 0.0005, Train: 100.00%, Valid: 68.40% Test: 67.70%\n",
      "Epoch: 74, Loss: 0.0010, Train: 100.00%, Valid: 68.40% Test: 67.90%\n",
      "Epoch: 75, Loss: 0.0001, Train: 100.00%, Valid: 68.00% Test: 67.80%\n",
      "Epoch: 76, Loss: 0.0005, Train: 100.00%, Valid: 67.80% Test: 67.80%\n",
      "Epoch: 77, Loss: 0.0013, Train: 100.00%, Valid: 67.40% Test: 67.30%\n",
      "Epoch: 78, Loss: 0.0032, Train: 100.00%, Valid: 67.20% Test: 67.00%\n",
      "Epoch: 79, Loss: 0.0044, Train: 100.00%, Valid: 67.40% Test: 67.30%\n",
      "Epoch: 80, Loss: 0.0025, Train: 100.00%, Valid: 67.60% Test: 67.40%\n",
      "Epoch: 81, Loss: 0.0004, Train: 100.00%, Valid: 67.60% Test: 66.90%\n",
      "Epoch: 82, Loss: 0.0178, Train: 100.00%, Valid: 67.80% Test: 67.50%\n",
      "Epoch: 83, Loss: 0.0007, Train: 100.00%, Valid: 67.60% Test: 67.00%\n",
      "Epoch: 84, Loss: 0.0051, Train: 100.00%, Valid: 67.60% Test: 67.50%\n",
      "Epoch: 85, Loss: 0.0226, Train: 100.00%, Valid: 67.80% Test: 67.50%\n",
      "Epoch: 86, Loss: 0.0001, Train: 100.00%, Valid: 66.80% Test: 67.50%\n",
      "Epoch: 87, Loss: 0.0093, Train: 100.00%, Valid: 67.20% Test: 67.50%\n",
      "Epoch: 88, Loss: 0.0002, Train: 100.00%, Valid: 66.80% Test: 67.30%\n",
      "Epoch: 89, Loss: 0.0001, Train: 100.00%, Valid: 66.80% Test: 67.20%\n",
      "Epoch: 90, Loss: 0.0003, Train: 100.00%, Valid: 66.40% Test: 66.70%\n",
      "Epoch: 91, Loss: 0.0009, Train: 100.00%, Valid: 66.20% Test: 66.30%\n",
      "Epoch: 92, Loss: 0.0000, Train: 100.00%, Valid: 66.80% Test: 66.40%\n",
      "Epoch: 93, Loss: 0.0009, Train: 100.00%, Valid: 66.40% Test: 66.20%\n",
      "Epoch: 94, Loss: 0.0010, Train: 100.00%, Valid: 66.00% Test: 66.00%\n",
      "Epoch: 95, Loss: 0.0003, Train: 100.00%, Valid: 65.40% Test: 65.70%\n",
      "Epoch: 96, Loss: 0.0006, Train: 100.00%, Valid: 65.80% Test: 65.90%\n",
      "Epoch: 97, Loss: 0.0083, Train: 100.00%, Valid: 67.00% Test: 66.00%\n",
      "Epoch: 98, Loss: 0.0003, Train: 100.00%, Valid: 67.20% Test: 66.60%\n",
      "Epoch: 99, Loss: 0.0003, Train: 100.00%, Valid: 68.00% Test: 66.70%\n",
      "Epoch: 100, Loss: 0.0000, Train: 100.00%, Valid: 67.80% Test: 66.60%\n",
      "Epoch: 101, Loss: 0.0000, Train: 100.00%, Valid: 67.40% Test: 66.50%\n",
      "Epoch: 102, Loss: 0.0006, Train: 100.00%, Valid: 67.20% Test: 66.30%\n",
      "Epoch: 103, Loss: 0.0056, Train: 100.00%, Valid: 67.60% Test: 66.60%\n",
      "Epoch: 104, Loss: 0.0002, Train: 100.00%, Valid: 67.40% Test: 66.20%\n",
      "Epoch: 105, Loss: 0.0017, Train: 100.00%, Valid: 67.60% Test: 66.50%\n",
      "Epoch: 106, Loss: 0.0003, Train: 100.00%, Valid: 67.80% Test: 66.40%\n",
      "Epoch: 107, Loss: 0.0022, Train: 100.00%, Valid: 67.60% Test: 66.30%\n",
      "Epoch: 108, Loss: 0.0002, Train: 100.00%, Valid: 67.60% Test: 66.40%\n",
      "Epoch: 109, Loss: 0.0001, Train: 100.00%, Valid: 67.60% Test: 66.30%\n",
      "Epoch: 110, Loss: 0.0008, Train: 100.00%, Valid: 67.40% Test: 66.20%\n",
      "Epoch: 111, Loss: 0.0006, Train: 100.00%, Valid: 67.60% Test: 66.20%\n",
      "Epoch: 112, Loss: 0.0008, Train: 100.00%, Valid: 67.60% Test: 66.40%\n",
      "Epoch: 113, Loss: 0.0000, Train: 100.00%, Valid: 67.60% Test: 66.50%\n",
      "Epoch: 114, Loss: 0.0010, Train: 100.00%, Valid: 67.60% Test: 66.60%\n",
      "Epoch: 115, Loss: 0.0020, Train: 100.00%, Valid: 67.40% Test: 66.50%\n",
      "Epoch: 116, Loss: 0.0071, Train: 100.00%, Valid: 67.40% Test: 66.30%\n",
      "Epoch: 117, Loss: 0.0004, Train: 100.00%, Valid: 67.40% Test: 66.30%\n",
      "Epoch: 118, Loss: 0.0003, Train: 100.00%, Valid: 67.20% Test: 66.30%\n",
      "Epoch: 119, Loss: 0.0083, Train: 100.00%, Valid: 67.00% Test: 66.10%\n",
      "Epoch: 120, Loss: 0.0014, Train: 100.00%, Valid: 66.60% Test: 65.80%\n",
      "Epoch: 121, Loss: 0.0004, Train: 100.00%, Valid: 66.80% Test: 65.50%\n",
      "Epoch: 122, Loss: 0.0003, Train: 100.00%, Valid: 66.80% Test: 65.60%\n",
      "Epoch: 123, Loss: 0.0016, Train: 100.00%, Valid: 66.80% Test: 65.60%\n",
      "Epoch: 124, Loss: 0.0063, Train: 100.00%, Valid: 67.00% Test: 65.60%\n",
      "Epoch: 125, Loss: 0.0036, Train: 100.00%, Valid: 66.80% Test: 65.50%\n",
      "Epoch: 126, Loss: 0.0000, Train: 100.00%, Valid: 66.80% Test: 65.60%\n",
      "Epoch: 127, Loss: 0.0003, Train: 100.00%, Valid: 66.20% Test: 65.20%\n",
      "Epoch: 128, Loss: 0.0020, Train: 100.00%, Valid: 66.40% Test: 65.20%\n",
      "Epoch: 129, Loss: 0.0171, Train: 100.00%, Valid: 66.20% Test: 65.30%\n",
      "Epoch: 130, Loss: 0.0078, Train: 100.00%, Valid: 66.40% Test: 65.50%\n",
      "Epoch: 131, Loss: 0.0001, Train: 100.00%, Valid: 66.60% Test: 64.90%\n",
      "Epoch: 132, Loss: 0.0002, Train: 100.00%, Valid: 66.60% Test: 64.80%\n",
      "Epoch: 133, Loss: 0.0110, Train: 100.00%, Valid: 67.20% Test: 65.40%\n",
      "Epoch: 134, Loss: 0.0006, Train: 100.00%, Valid: 67.40% Test: 65.90%\n",
      "Epoch: 135, Loss: 0.0179, Train: 100.00%, Valid: 67.80% Test: 65.70%\n",
      "Epoch: 136, Loss: 0.0141, Train: 100.00%, Valid: 67.20% Test: 66.00%\n",
      "Epoch: 137, Loss: 0.0002, Train: 100.00%, Valid: 67.00% Test: 65.60%\n",
      "Epoch: 138, Loss: 0.0005, Train: 100.00%, Valid: 66.60% Test: 65.40%\n",
      "Epoch: 139, Loss: 0.0003, Train: 100.00%, Valid: 66.60% Test: 65.30%\n",
      "Epoch: 140, Loss: 0.0003, Train: 100.00%, Valid: 66.60% Test: 65.10%\n",
      "Epoch: 141, Loss: 0.0020, Train: 100.00%, Valid: 66.40% Test: 64.90%\n",
      "Epoch: 142, Loss: 0.0005, Train: 100.00%, Valid: 66.40% Test: 65.00%\n",
      "Epoch: 143, Loss: 0.0001, Train: 100.00%, Valid: 66.00% Test: 64.90%\n",
      "Epoch: 144, Loss: 0.0007, Train: 100.00%, Valid: 65.80% Test: 65.00%\n",
      "Epoch: 145, Loss: 0.0009, Train: 100.00%, Valid: 66.00% Test: 65.00%\n",
      "Epoch: 146, Loss: 0.0001, Train: 100.00%, Valid: 66.00% Test: 64.70%\n",
      "Epoch: 147, Loss: 0.0000, Train: 100.00%, Valid: 65.80% Test: 64.50%\n",
      "Epoch: 148, Loss: 0.0063, Train: 100.00%, Valid: 66.20% Test: 64.90%\n",
      "Epoch: 149, Loss: 0.0125, Train: 100.00%, Valid: 66.20% Test: 65.60%\n",
      "Epoch: 150, Loss: 0.0078, Train: 100.00%, Valid: 66.80% Test: 65.40%\n",
      "Best model: Train: 100.00%, Valid: 68.80% Test: 68.00%\n"
     ]
    }
   ],
   "source": [
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "bisection_best_model, bisection_accs = train(graphs, [graph_train, graph_val, graph_test], args, model, optimizer, mode=\"community\")\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], bisection_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5PROPwoOVcJy"
   },
   "source": [
    "## Greedy Preprocess"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "id": "h3DVamWqVT92"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Partition the graph in to 20 communities\n",
      "Each community has 121 nodes in average\n",
      "Each community has 222 edges in average\n"
     ]
    }
   ],
   "source": [
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "graphs = preprocess(graph_train.G, graph_train.node_label_index, method=\"greedy\")\n",
    "print(\"Partition the graph in to {} communities\".format(len(graphs)))\n",
    "avg_num_nodes = 0\n",
    "avg_num_edges = 0\n",
    "for graph in graphs:\n",
    "    avg_num_nodes += graph.num_nodes\n",
    "    avg_num_edges += graph.num_edges\n",
    "avg_num_nodes = int(avg_num_nodes / len(graphs))\n",
    "avg_num_edges = int(avg_num_edges / len(graphs))\n",
    "print(\"Each community has {} nodes in average\".format(avg_num_nodes))\n",
    "print(\"Each community has {} edges in average\".format(avg_num_edges))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "93pR_-kxVgma"
   },
   "source": [
    "## Greedy Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "id": "lQgQY-jPVd_U"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 01, Loss: 1.9139, Train: 16.43%, Valid: 30.80% Test: 31.80%\n",
      "Epoch: 02, Loss: 2.4561, Train: 15.71%, Valid: 30.60% Test: 29.90%\n",
      "Epoch: 03, Loss: 1.8191, Train: 24.29%, Valid: 29.00% Test: 27.70%\n",
      "Epoch: 04, Loss: 2.3316, Train: 25.71%, Valid: 27.60% Test: 28.20%\n",
      "Epoch: 05, Loss: 1.2574, Train: 26.43%, Valid: 34.00% Test: 32.50%\n",
      "Epoch: 06, Loss: 1.8178, Train: 24.29%, Valid: 32.80% Test: 31.90%\n",
      "Epoch: 07, Loss: 0.4583, Train: 24.29%, Valid: 30.20% Test: 30.60%\n",
      "Epoch: 08, Loss: 2.1879, Train: 24.29%, Valid: 27.60% Test: 28.70%\n",
      "Epoch: 09, Loss: 1.2582, Train: 23.57%, Valid: 26.60% Test: 27.60%\n",
      "Epoch: 10, Loss: 3.8275, Train: 23.57%, Valid: 26.00% Test: 26.20%\n",
      "Epoch: 11, Loss: 1.6548, Train: 25.00%, Valid: 25.20% Test: 25.20%\n",
      "Epoch: 12, Loss: 0.4159, Train: 27.14%, Valid: 23.40% Test: 24.50%\n",
      "Epoch: 13, Loss: 1.0413, Train: 27.14%, Valid: 24.00% Test: 25.00%\n",
      "Epoch: 14, Loss: 0.8986, Train: 32.86%, Valid: 25.60% Test: 26.10%\n",
      "Epoch: 15, Loss: 1.4616, Train: 36.43%, Valid: 23.60% Test: 25.70%\n",
      "Epoch: 16, Loss: 0.9036, Train: 39.29%, Valid: 23.80% Test: 24.80%\n",
      "Epoch: 17, Loss: 0.9141, Train: 40.71%, Valid: 22.20% Test: 22.30%\n",
      "Epoch: 18, Loss: 0.0169, Train: 41.43%, Valid: 21.40% Test: 22.10%\n",
      "Epoch: 19, Loss: 0.0133, Train: 45.00%, Valid: 19.60% Test: 20.20%\n",
      "Epoch: 20, Loss: 0.1968, Train: 43.57%, Valid: 19.80% Test: 19.90%\n",
      "Epoch: 21, Loss: 0.1634, Train: 44.29%, Valid: 21.40% Test: 22.50%\n",
      "Epoch: 22, Loss: 3.1035, Train: 46.43%, Valid: 22.40% Test: 23.20%\n",
      "Epoch: 23, Loss: 0.0147, Train: 47.14%, Valid: 23.20% Test: 24.10%\n",
      "Epoch: 24, Loss: 0.4705, Train: 47.14%, Valid: 24.80% Test: 24.80%\n",
      "Epoch: 25, Loss: 2.0545, Train: 47.14%, Valid: 26.20% Test: 25.80%\n",
      "Epoch: 26, Loss: 2.8858, Train: 47.86%, Valid: 27.40% Test: 26.40%\n",
      "Epoch: 27, Loss: 0.0041, Train: 52.14%, Valid: 29.00% Test: 28.90%\n",
      "Epoch: 28, Loss: 0.0089, Train: 55.71%, Valid: 30.00% Test: 29.10%\n",
      "Epoch: 29, Loss: 0.5899, Train: 55.71%, Valid: 31.20% Test: 31.10%\n",
      "Epoch: 30, Loss: 0.1277, Train: 57.86%, Valid: 32.20% Test: 32.20%\n",
      "Epoch: 31, Loss: 0.8968, Train: 57.14%, Valid: 33.60% Test: 33.50%\n",
      "Epoch: 32, Loss: 0.6216, Train: 56.43%, Valid: 34.20% Test: 35.50%\n",
      "Epoch: 33, Loss: 4.3143, Train: 54.29%, Valid: 34.40% Test: 36.30%\n",
      "Epoch: 34, Loss: 2.6306, Train: 50.00%, Valid: 34.80% Test: 36.20%\n",
      "Epoch: 35, Loss: 0.3018, Train: 51.43%, Valid: 34.80% Test: 36.30%\n",
      "Epoch: 36, Loss: 0.2736, Train: 51.43%, Valid: 35.40% Test: 35.60%\n",
      "Epoch: 37, Loss: 2.1307, Train: 50.71%, Valid: 35.00% Test: 34.20%\n",
      "Epoch: 38, Loss: 0.0006, Train: 49.29%, Valid: 34.20% Test: 33.70%\n",
      "Epoch: 39, Loss: 0.3358, Train: 53.57%, Valid: 33.60% Test: 32.50%\n",
      "Epoch: 40, Loss: 0.0009, Train: 58.57%, Valid: 34.60% Test: 32.50%\n",
      "Epoch: 41, Loss: 0.0223, Train: 59.29%, Valid: 34.40% Test: 32.30%\n",
      "Epoch: 42, Loss: 0.0014, Train: 60.00%, Valid: 33.20% Test: 32.80%\n",
      "Epoch: 43, Loss: 0.0003, Train: 60.00%, Valid: 33.00% Test: 32.90%\n",
      "Epoch: 44, Loss: 2.1065, Train: 62.86%, Valid: 33.80% Test: 32.80%\n",
      "Epoch: 45, Loss: 0.0403, Train: 65.71%, Valid: 33.00% Test: 31.70%\n",
      "Epoch: 46, Loss: 0.2361, Train: 64.29%, Valid: 30.20% Test: 31.70%\n",
      "Epoch: 47, Loss: 0.8438, Train: 65.71%, Valid: 29.80% Test: 30.80%\n",
      "Epoch: 48, Loss: 1.8956, Train: 66.43%, Valid: 28.80% Test: 30.70%\n",
      "Epoch: 49, Loss: 1.0811, Train: 72.86%, Valid: 28.40% Test: 30.60%\n",
      "Epoch: 50, Loss: 4.6678, Train: 77.14%, Valid: 27.40% Test: 30.90%\n",
      "Epoch: 51, Loss: 0.0470, Train: 78.57%, Valid: 26.80% Test: 30.10%\n",
      "Epoch: 52, Loss: 1.5683, Train: 82.86%, Valid: 25.40% Test: 29.40%\n",
      "Epoch: 53, Loss: 0.0489, Train: 83.57%, Valid: 26.00% Test: 29.20%\n",
      "Epoch: 54, Loss: 0.5771, Train: 85.00%, Valid: 26.80% Test: 28.80%\n",
      "Epoch: 55, Loss: 0.5900, Train: 81.43%, Valid: 26.00% Test: 26.60%\n",
      "Epoch: 56, Loss: 0.9991, Train: 84.29%, Valid: 23.00% Test: 24.50%\n",
      "Epoch: 57, Loss: 2.0713, Train: 84.29%, Valid: 20.00% Test: 21.80%\n",
      "Epoch: 58, Loss: 0.2328, Train: 86.43%, Valid: 18.60% Test: 20.60%\n",
      "Epoch: 59, Loss: 0.3730, Train: 86.43%, Valid: 18.20% Test: 20.70%\n",
      "Epoch: 60, Loss: 0.4065, Train: 86.43%, Valid: 17.80% Test: 20.10%\n",
      "Epoch: 61, Loss: 0.7238, Train: 86.43%, Valid: 19.20% Test: 20.60%\n",
      "Epoch: 62, Loss: 0.0844, Train: 85.71%, Valid: 19.20% Test: 20.50%\n",
      "Epoch: 63, Loss: 0.6287, Train: 84.29%, Valid: 20.80% Test: 21.70%\n",
      "Epoch: 64, Loss: 1.2611, Train: 87.14%, Valid: 22.20% Test: 23.60%\n",
      "Epoch: 65, Loss: 0.0654, Train: 87.86%, Valid: 24.40% Test: 25.20%\n",
      "Epoch: 66, Loss: 0.8254, Train: 88.57%, Valid: 26.00% Test: 27.30%\n",
      "Epoch: 67, Loss: 0.0000, Train: 87.86%, Valid: 25.80% Test: 26.90%\n",
      "Epoch: 68, Loss: 0.1056, Train: 87.86%, Valid: 24.60% Test: 26.80%\n",
      "Epoch: 69, Loss: 0.1844, Train: 87.14%, Valid: 25.00% Test: 27.40%\n",
      "Epoch: 70, Loss: 0.0252, Train: 84.29%, Valid: 23.60% Test: 26.50%\n",
      "Epoch: 71, Loss: 0.2668, Train: 83.57%, Valid: 24.00% Test: 25.70%\n",
      "Epoch: 72, Loss: 0.0343, Train: 81.43%, Valid: 23.40% Test: 26.10%\n",
      "Epoch: 73, Loss: 0.0008, Train: 81.43%, Valid: 22.60% Test: 25.10%\n",
      "Epoch: 74, Loss: 3.7004, Train: 80.71%, Valid: 22.40% Test: 24.90%\n",
      "Epoch: 75, Loss: 1.1943, Train: 81.43%, Valid: 22.40% Test: 24.80%\n",
      "Epoch: 76, Loss: 0.0033, Train: 80.71%, Valid: 23.00% Test: 26.00%\n",
      "Epoch: 77, Loss: 0.0000, Train: 82.86%, Valid: 22.40% Test: 25.10%\n",
      "Epoch: 78, Loss: 0.0290, Train: 83.57%, Valid: 22.60% Test: 25.50%\n",
      "Epoch: 79, Loss: 0.0007, Train: 82.86%, Valid: 21.60% Test: 24.20%\n",
      "Epoch: 80, Loss: 0.0057, Train: 82.86%, Valid: 22.20% Test: 24.00%\n",
      "Epoch: 81, Loss: 0.7980, Train: 83.57%, Valid: 23.00% Test: 24.70%\n",
      "Epoch: 82, Loss: 0.0000, Train: 83.57%, Valid: 21.80% Test: 24.70%\n",
      "Epoch: 83, Loss: 0.0360, Train: 82.86%, Valid: 21.60% Test: 24.40%\n",
      "Epoch: 84, Loss: 0.0001, Train: 82.14%, Valid: 21.80% Test: 24.90%\n",
      "Epoch: 85, Loss: 0.3733, Train: 83.57%, Valid: 24.00% Test: 24.80%\n",
      "Epoch: 86, Loss: 1.0987, Train: 83.57%, Valid: 23.20% Test: 24.30%\n",
      "Epoch: 87, Loss: 0.0011, Train: 83.57%, Valid: 23.40% Test: 24.70%\n",
      "Epoch: 88, Loss: 0.0376, Train: 83.57%, Valid: 24.40% Test: 25.00%\n",
      "Epoch: 89, Loss: 0.0866, Train: 85.71%, Valid: 24.20% Test: 25.90%\n",
      "Epoch: 90, Loss: 0.8986, Train: 86.43%, Valid: 24.60% Test: 26.30%\n",
      "Epoch: 91, Loss: 0.0909, Train: 87.86%, Valid: 24.40% Test: 26.10%\n",
      "Epoch: 92, Loss: 0.0397, Train: 87.14%, Valid: 24.40% Test: 26.30%\n",
      "Epoch: 93, Loss: 1.2672, Train: 87.14%, Valid: 25.20% Test: 26.10%\n",
      "Epoch: 94, Loss: 0.0301, Train: 87.86%, Valid: 25.00% Test: 25.70%\n",
      "Epoch: 95, Loss: 0.0504, Train: 88.57%, Valid: 26.00% Test: 26.50%\n",
      "Epoch: 96, Loss: 0.2063, Train: 90.00%, Valid: 25.80% Test: 27.80%\n",
      "Epoch: 97, Loss: 0.1737, Train: 90.00%, Valid: 26.00% Test: 28.00%\n",
      "Epoch: 98, Loss: 0.0141, Train: 90.71%, Valid: 26.80% Test: 28.40%\n",
      "Epoch: 99, Loss: 0.1525, Train: 90.71%, Valid: 25.20% Test: 27.40%\n",
      "Epoch: 100, Loss: 0.5350, Train: 90.71%, Valid: 26.20% Test: 27.50%\n",
      "Epoch: 101, Loss: 0.4606, Train: 90.71%, Valid: 27.20% Test: 27.40%\n",
      "Epoch: 102, Loss: 0.3215, Train: 90.71%, Valid: 27.40% Test: 27.60%\n",
      "Epoch: 103, Loss: 0.0261, Train: 90.71%, Valid: 26.20% Test: 27.30%\n",
      "Epoch: 104, Loss: 0.0176, Train: 90.71%, Valid: 26.60% Test: 27.40%\n",
      "Epoch: 105, Loss: 0.0010, Train: 90.71%, Valid: 27.60% Test: 27.70%\n",
      "Epoch: 106, Loss: 0.0764, Train: 90.71%, Valid: 28.40% Test: 27.90%\n",
      "Epoch: 107, Loss: 0.0942, Train: 91.43%, Valid: 29.40% Test: 28.30%\n",
      "Epoch: 108, Loss: 0.0031, Train: 91.43%, Valid: 29.00% Test: 28.50%\n",
      "Epoch: 109, Loss: 0.0846, Train: 91.43%, Valid: 29.00% Test: 28.50%\n",
      "Epoch: 110, Loss: 0.0313, Train: 91.43%, Valid: 27.40% Test: 27.50%\n",
      "Epoch: 111, Loss: 0.0494, Train: 91.43%, Valid: 28.40% Test: 27.60%\n",
      "Epoch: 112, Loss: 0.0996, Train: 91.43%, Valid: 28.60% Test: 27.90%\n",
      "Epoch: 113, Loss: 0.4673, Train: 91.43%, Valid: 29.20% Test: 28.30%\n",
      "Epoch: 114, Loss: 0.0578, Train: 91.43%, Valid: 28.40% Test: 28.50%\n",
      "Epoch: 115, Loss: 0.0753, Train: 91.43%, Valid: 28.20% Test: 29.30%\n",
      "Epoch: 116, Loss: 0.0000, Train: 91.43%, Valid: 27.20% Test: 30.20%\n",
      "Epoch: 117, Loss: 0.1975, Train: 91.43%, Valid: 27.80% Test: 30.20%\n",
      "Epoch: 118, Loss: 0.1254, Train: 91.43%, Valid: 27.60% Test: 29.80%\n",
      "Epoch: 119, Loss: 0.0250, Train: 90.71%, Valid: 27.60% Test: 29.50%\n",
      "Epoch: 120, Loss: 0.0065, Train: 90.71%, Valid: 27.60% Test: 29.40%\n",
      "Epoch: 121, Loss: 0.0104, Train: 90.71%, Valid: 26.80% Test: 29.90%\n",
      "Epoch: 122, Loss: 0.0221, Train: 90.71%, Valid: 27.20% Test: 29.60%\n",
      "Epoch: 123, Loss: 0.0445, Train: 90.71%, Valid: 27.00% Test: 29.20%\n",
      "Epoch: 124, Loss: 0.0047, Train: 90.71%, Valid: 27.00% Test: 28.80%\n",
      "Epoch: 125, Loss: 0.1971, Train: 90.71%, Valid: 27.60% Test: 29.10%\n",
      "Epoch: 126, Loss: 0.3074, Train: 90.71%, Valid: 27.60% Test: 28.70%\n",
      "Epoch: 127, Loss: 0.0240, Train: 91.43%, Valid: 28.20% Test: 28.30%\n",
      "Epoch: 128, Loss: 0.0000, Train: 91.43%, Valid: 28.60% Test: 28.80%\n",
      "Epoch: 129, Loss: 0.0104, Train: 91.43%, Valid: 29.00% Test: 29.10%\n",
      "Epoch: 130, Loss: 0.0000, Train: 91.43%, Valid: 29.00% Test: 29.30%\n",
      "Epoch: 131, Loss: 0.0063, Train: 91.43%, Valid: 29.00% Test: 29.10%\n",
      "Epoch: 132, Loss: 0.0900, Train: 91.43%, Valid: 29.20% Test: 28.50%\n",
      "Epoch: 133, Loss: 0.0259, Train: 91.43%, Valid: 28.60% Test: 28.30%\n",
      "Epoch: 134, Loss: 0.0758, Train: 91.43%, Valid: 28.20% Test: 28.20%\n",
      "Epoch: 135, Loss: 0.0262, Train: 91.43%, Valid: 28.80% Test: 28.10%\n",
      "Epoch: 136, Loss: 0.0164, Train: 91.43%, Valid: 29.00% Test: 28.90%\n",
      "Epoch: 137, Loss: 0.0001, Train: 91.43%, Valid: 29.00% Test: 29.40%\n",
      "Epoch: 138, Loss: 0.2173, Train: 91.43%, Valid: 29.20% Test: 28.80%\n",
      "Epoch: 139, Loss: 0.7242, Train: 91.43%, Valid: 28.60% Test: 28.60%\n",
      "Epoch: 140, Loss: 0.2622, Train: 91.43%, Valid: 28.80% Test: 28.80%\n",
      "Epoch: 141, Loss: 0.0928, Train: 91.43%, Valid: 28.60% Test: 29.00%\n",
      "Epoch: 142, Loss: 0.0033, Train: 91.43%, Valid: 28.80% Test: 29.00%\n",
      "Epoch: 143, Loss: 0.0064, Train: 91.43%, Valid: 28.20% Test: 29.00%\n",
      "Epoch: 144, Loss: 0.0312, Train: 91.43%, Valid: 28.60% Test: 29.00%\n",
      "Epoch: 145, Loss: 0.0193, Train: 92.14%, Valid: 28.40% Test: 29.20%\n",
      "Epoch: 146, Loss: 0.0092, Train: 91.43%, Valid: 28.00% Test: 28.20%\n",
      "Epoch: 147, Loss: 0.0005, Train: 92.14%, Valid: 27.00% Test: 27.40%\n",
      "Epoch: 148, Loss: 0.0706, Train: 91.43%, Valid: 27.40% Test: 27.50%\n",
      "Epoch: 149, Loss: 0.1388, Train: 92.14%, Valid: 26.60% Test: 28.20%\n",
      "Epoch: 150, Loss: 0.0228, Train: 92.14%, Valid: 27.80% Test: 28.60%\n",
      "Best model: Train: 51.43%, Valid: 35.40% Test: 35.60%\n"
     ]
    }
   ],
   "source": [
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "greedy_best_model, greedy_accs = train(graphs, [graph_train, graph_val, graph_test], args, model, optimizer, mode=\"community\")\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], greedy_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "D5edKKT6Vk1C"
   },
   "source": [
    "## Full-Batch Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "id": "N5tIXxC8ViFD"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index fields: train_mask ignored.\n",
      "Index fields: val_mask ignored.\n",
      "Index fields: test_mask ignored.\n",
      "Epoch: 01, Loss: 1.9761, Train: 52.14%, Valid: 38.00% Test: 38.60%\n",
      "Epoch: 02, Loss: 1.1659, Train: 92.14%, Valid: 53.60% Test: 54.40%\n",
      "Epoch: 03, Loss: 0.6200, Train: 99.29%, Valid: 63.00% Test: 66.30%\n",
      "Epoch: 04, Loss: 0.3160, Train: 100.00%, Valid: 69.80% Test: 72.20%\n",
      "Epoch: 05, Loss: 0.1682, Train: 100.00%, Valid: 71.00% Test: 73.70%\n",
      "Epoch: 06, Loss: 0.0711, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 07, Loss: 0.0398, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 08, Loss: 0.0332, Train: 100.00%, Valid: 72.20% Test: 72.90%\n",
      "Epoch: 09, Loss: 0.0136, Train: 100.00%, Valid: 72.20% Test: 73.40%\n",
      "Epoch: 10, Loss: 0.0058, Train: 100.00%, Valid: 72.40% Test: 73.50%\n",
      "Epoch: 11, Loss: 0.0063, Train: 100.00%, Valid: 72.20% Test: 73.60%\n",
      "Epoch: 12, Loss: 0.0018, Train: 100.00%, Valid: 72.20% Test: 73.80%\n",
      "Epoch: 13, Loss: 0.0016, Train: 100.00%, Valid: 72.80% Test: 73.90%\n",
      "Epoch: 14, Loss: 0.0028, Train: 100.00%, Valid: 72.60% Test: 74.30%\n",
      "Epoch: 15, Loss: 0.0044, Train: 100.00%, Valid: 72.00% Test: 74.70%\n",
      "Epoch: 16, Loss: 0.0013, Train: 100.00%, Valid: 72.00% Test: 74.90%\n",
      "Epoch: 17, Loss: 0.0005, Train: 100.00%, Valid: 72.00% Test: 75.00%\n",
      "Epoch: 18, Loss: 0.0003, Train: 100.00%, Valid: 71.40% Test: 74.90%\n",
      "Epoch: 19, Loss: 0.0006, Train: 100.00%, Valid: 71.40% Test: 74.70%\n",
      "Epoch: 20, Loss: 0.0002, Train: 100.00%, Valid: 71.20% Test: 74.60%\n",
      "Epoch: 21, Loss: 0.0003, Train: 100.00%, Valid: 72.00% Test: 74.70%\n",
      "Epoch: 22, Loss: 0.0018, Train: 100.00%, Valid: 71.80% Test: 74.80%\n",
      "Epoch: 23, Loss: 0.0093, Train: 100.00%, Valid: 71.40% Test: 75.10%\n",
      "Epoch: 24, Loss: 0.0001, Train: 100.00%, Valid: 71.40% Test: 75.00%\n",
      "Epoch: 25, Loss: 0.0002, Train: 100.00%, Valid: 71.60% Test: 75.30%\n",
      "Epoch: 26, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 75.40%\n",
      "Epoch: 27, Loss: 0.0015, Train: 100.00%, Valid: 72.20% Test: 75.10%\n",
      "Epoch: 28, Loss: 0.0002, Train: 100.00%, Valid: 71.80% Test: 75.00%\n",
      "Epoch: 29, Loss: 0.0001, Train: 100.00%, Valid: 72.00% Test: 74.70%\n",
      "Epoch: 30, Loss: 0.0001, Train: 100.00%, Valid: 72.00% Test: 74.50%\n",
      "Epoch: 31, Loss: 0.0001, Train: 100.00%, Valid: 71.40% Test: 74.20%\n",
      "Epoch: 32, Loss: 0.0003, Train: 100.00%, Valid: 71.00% Test: 74.10%\n",
      "Epoch: 33, Loss: 0.0002, Train: 100.00%, Valid: 71.20% Test: 74.10%\n",
      "Epoch: 34, Loss: 0.0002, Train: 100.00%, Valid: 71.40% Test: 74.10%\n",
      "Epoch: 35, Loss: 0.0003, Train: 100.00%, Valid: 71.40% Test: 74.10%\n",
      "Epoch: 36, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 74.00%\n",
      "Epoch: 37, Loss: 0.0002, Train: 100.00%, Valid: 71.60% Test: 73.90%\n",
      "Epoch: 38, Loss: 0.0002, Train: 100.00%, Valid: 71.60% Test: 74.00%\n",
      "Epoch: 39, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 74.00%\n",
      "Epoch: 40, Loss: 0.0002, Train: 100.00%, Valid: 71.60% Test: 73.90%\n",
      "Epoch: 41, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 74.00%\n",
      "Epoch: 42, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 74.00%\n",
      "Epoch: 43, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.90%\n",
      "Epoch: 44, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.80%\n",
      "Epoch: 45, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.80%\n",
      "Epoch: 46, Loss: 0.0002, Train: 100.00%, Valid: 71.80% Test: 73.80%\n",
      "Epoch: 47, Loss: 0.0005, Train: 100.00%, Valid: 71.80% Test: 73.80%\n",
      "Epoch: 48, Loss: 0.0003, Train: 100.00%, Valid: 71.80% Test: 73.80%\n",
      "Epoch: 49, Loss: 0.0002, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 50, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 51, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 52, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 53, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 54, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 55, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 56, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 57, Loss: 0.0016, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 58, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.60%\n",
      "Epoch: 59, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 60, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 61, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 62, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 63, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 64, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 65, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 66, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 67, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 68, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 69, Loss: 0.0002, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 70, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 71, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 72, Loss: 0.0000, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 73, Loss: 0.0005, Train: 100.00%, Valid: 71.80% Test: 73.60%\n",
      "Epoch: 74, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.70%\n",
      "Epoch: 75, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.80%\n",
      "Epoch: 76, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 77, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 78, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 79, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 80, Loss: 0.0003, Train: 100.00%, Valid: 71.60% Test: 73.70%\n",
      "Epoch: 81, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.60%\n",
      "Epoch: 82, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.60%\n",
      "Epoch: 83, Loss: 0.0001, Train: 100.00%, Valid: 71.60% Test: 73.60%\n",
      "Epoch: 84, Loss: 0.0001, Train: 100.00%, Valid: 71.80% Test: 73.50%\n",
      "Epoch: 85, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.50%\n",
      "Epoch: 86, Loss: 0.0000, Train: 100.00%, Valid: 71.60% Test: 73.50%\n",
      "Epoch: 87, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 88, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 89, Loss: 0.0001, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 90, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 91, Loss: 0.0002, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 92, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 93, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 94, Loss: 0.0001, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 95, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 96, Loss: 0.0003, Train: 100.00%, Valid: 71.40% Test: 73.40%\n",
      "Epoch: 97, Loss: 0.0001, Train: 100.00%, Valid: 71.40% Test: 73.50%\n",
      "Epoch: 98, Loss: 0.0001, Train: 100.00%, Valid: 71.40% Test: 73.50%\n",
      "Epoch: 99, Loss: 0.0002, Train: 100.00%, Valid: 71.40% Test: 73.30%\n",
      "Epoch: 100, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.30%\n",
      "Epoch: 101, Loss: 0.0003, Train: 100.00%, Valid: 71.40% Test: 73.30%\n",
      "Epoch: 102, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.40%\n",
      "Epoch: 103, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.50%\n",
      "Epoch: 104, Loss: 0.0001, Train: 100.00%, Valid: 71.20% Test: 73.50%\n",
      "Epoch: 105, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 106, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 107, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 108, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 109, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 110, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 111, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 112, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 113, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 114, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 115, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 116, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 117, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 118, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 119, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 120, Loss: 0.0000, Train: 100.00%, Valid: 70.80% Test: 73.50%\n",
      "Epoch: 121, Loss: 0.0000, Train: 100.00%, Valid: 70.80% Test: 73.50%\n",
      "Epoch: 122, Loss: 0.0001, Train: 100.00%, Valid: 70.80% Test: 73.50%\n",
      "Epoch: 123, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 124, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.40%\n",
      "Epoch: 125, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 126, Loss: 0.0015, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 127, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 128, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.50%\n",
      "Epoch: 129, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.70%\n",
      "Epoch: 130, Loss: 0.0003, Train: 100.00%, Valid: 70.80% Test: 73.70%\n",
      "Epoch: 131, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.60%\n",
      "Epoch: 132, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.60%\n",
      "Epoch: 133, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.70%\n",
      "Epoch: 134, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.60%\n",
      "Epoch: 135, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.50%\n",
      "Epoch: 136, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.60%\n",
      "Epoch: 137, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.70%\n",
      "Epoch: 138, Loss: 0.0001, Train: 100.00%, Valid: 71.20% Test: 73.80%\n",
      "Epoch: 139, Loss: 0.0000, Train: 100.00%, Valid: 71.40% Test: 73.90%\n",
      "Epoch: 140, Loss: 0.0000, Train: 100.00%, Valid: 71.20% Test: 73.90%\n",
      "Epoch: 141, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.90%\n",
      "Epoch: 142, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.90%\n",
      "Epoch: 143, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.80%\n",
      "Epoch: 144, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.80%\n",
      "Epoch: 145, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.80%\n",
      "Epoch: 146, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.80%\n",
      "Epoch: 147, Loss: 0.0000, Train: 100.00%, Valid: 71.00% Test: 73.70%\n",
      "Epoch: 148, Loss: 0.0001, Train: 100.00%, Valid: 71.00% Test: 73.70%\n",
      "Epoch: 149, Loss: 0.0001, Train: 100.00%, Valid: 71.20% Test: 73.70%\n",
      "Epoch: 150, Loss: 0.0001, Train: 100.00%, Valid: 71.20% Test: 73.60%\n",
      "Best model: Train: 100.00%, Valid: 72.80% Test: 73.90%\n"
     ]
    }
   ],
   "source": [
    "graphs_train, graphs_val, graphs_test = \\\n",
    "    GraphDataset.pyg_to_graphs(pyg_dataset, verbose=True, fixed_split=True)\n",
    "\n",
    "graph_train = graphs_train[0]\n",
    "graph_val = graphs_val[0]\n",
    "graph_test = graphs_test[0]\n",
    "\n",
    "model = GNN(graph_train.num_node_features, args['hidden_size'], graph_train.num_node_labels, args).to(args['device'])\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=args['lr'])\n",
    "graphs = [graph_train, graph_val, graph_test]\n",
    "all_best_model, all_accs = train(graphs, graphs, args, model, optimizer, mode=\"all\")\n",
    "train_acc, val_acc, test_acc = test([graph_train, graph_val, graph_test], all_best_model)\n",
    "print('Best model:',\n",
    "      f'Train: {100 * train_acc:.2f}%, '\n",
    "      f'Valid: {100 * val_acc:.2f}% '\n",
    "      f'Test: {100 * test_acc:.2f}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6RpuETv7Vpx0"
   },
   "source": [
    "## Visualization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "id": "PMK33kY5VmF5"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 648x504 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "louvain_results = np.array(louvain_accs)\n",
    "bisection_results = np.array(bisection_accs)\n",
    "greedy_results = np.array(greedy_accs)\n",
    "all_results = np.array(all_accs)\n",
    "\n",
    "x = np.arange(1, 151)\n",
    "\n",
    "plt.figure(figsize=(9, 7))\n",
    "\n",
    "plt.plot(x, louvain_results[:, 1], label=\"Louvain Validation\")\n",
    "plt.plot(x, louvain_results[:, 2], label=\"Louvain Test\")\n",
    "plt.plot(x, bisection_results[:, 1], label=\"Bisection Validation\")\n",
    "plt.plot(x, bisection_results[:, 2], label=\"Bisection Test\")\n",
    "plt.plot(x, greedy_results[:, 1], label=\"Greedy Validation\")\n",
    "plt.plot(x, greedy_results[:, 2], label=\"Greedy Test\")\n",
    "plt.plot(x, all_results[:, 1], label=\"All Validation\")\n",
    "plt.plot(x, all_results[:, 2], label=\"All Test\")\n",
    "plt.title('Model Accuracy')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> Where of what's past is prologue."
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "machine_shape": "hm",
   "name": "CS224W - Colab 5.ipynb",
   "provenance": [],
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
